0

The C++ standard says that accessing a non-active union member is UB.

But it states an exception from this rule for structs with a common-initial-sequence.

The following is such an example:

template<typename T>
struct A {
    T e0;
    T e1;
    T e2;
};
template<typename T>
struct B {
    T e0;
    T e1;
    T e2;
};
template<typename T>
union AB {
    A<T> a;
    B<T> b;
};

template<typename T>
constexpr char test() {
    AB<T> ab;
    ab.a.e0 = 1; 
    return ab.b.e0;
}

int main() {
    constexpr auto t1 = test<char>();    
}

UB is not allowed in constexpr-contexts, but the call to test() in main() results in an error at least for gcc. Why is this UB, although the C++ standard states the exception for this?

The error (g++) is:

In function 'int main()': bm62.cc:107:35: in 'constexpr' expansion of 'test()' bm62.cc:107:36: error: accessing 'AB::b' member instead of initialized 'AB::a' member in constant expression 107 | constexpr auto t1 = test();

wimalopaan
  • 4,838
  • 1
  • 21
  • 39
  • I think the compiler doesn't know when evaulating the `constexpr` that the 2 classes initial sequence are the same – Botond Horváth Oct 20 '22 at 10:28
  • The lack of UB is not what is causing the error. You can't have a `constexpr` that refers to a non-active member of a union. See [this answer](https://stackoverflow.com/a/32624191/10871073). (Possible duplicate?) It's now in #5.10 of [expr.const](https://eel.is/c++draft/expr.const) – Adrian Mole Oct 20 '22 at 10:38
  • please include the compiler error in the question, I get a couple of errors, but none is related to accessing non active member afaict https://godbolt.org/z/arbnxdscP – 463035818_is_not_an_ai Oct 20 '22 at 10:46
  • 1
    @463035818_is_not_a_number Changing OP's code to use `AB ab = {{1,2,3}};` (and removing the assignment line) shows that the post I linked does, in fact, answer the question. I'm closing as a dupe - feel free to comment (or revert) if you disagree. [Modified Godbolt Sample](https://godbolt.org/z/a3nEGs9qq) – Adrian Mole Oct 20 '22 at 10:52
  • See error above (edit): it is clear the misuse of the inactive member – wimalopaan Oct 20 '22 at 11:16
  • The standard says that it is ok to read the non-active member if the structs inside the union have a common-initial sequence, which is true for the above. – wimalopaan Oct 20 '22 at 11:17
  • 1
    The Standard says it's OK to read the inactive member in such cases (i.e. at **run-time**) ... but the Standard also says that doing so is not valid in a `constexpr`. – Adrian Mole Oct 20 '22 at 11:21
  • 1
    The 'exception' [clause I linked](https://eel.is/c++draft/expr.const#5.10) in my first comment: *an lvalue-to-rvalue conversion that is applied to a glvalue that refers to a non-active member of a union*. Now, the assignment operator is a clear case of lvalue-to-rvalue conversion. – Adrian Mole Oct 20 '22 at 11:24
  • But in https://eel.is/c++draft/class.union#general Note-1 explicitly defines such an exception. – wimalopaan Oct 20 '22 at 11:30
  • No. You can't just "pick and choose" the parts of the Standard that you like. Your case is not UB but it is also **explicitly not allowed** in a `constexpr`. – Adrian Mole Oct 20 '22 at 11:35

0 Answers0