https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127247

            Bug ID: 127247
           Summary: UB free bit_cast is not optimized away to simpler
                    assembly
           Product: gcc
           Version: 16.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: uchanahome8 at gmail dot com
  Target Milestone: ---

Hi, consider the following example: https://godbolt.org/z/Kc8c6Gjon. Here is
the code:

```
#include <bit>
#include <array>
#include <algorithm>

struct B {
    double value{1};
};

struct C {
    double value{2};
};

struct A {
    B b;
    C c;
};

constexpr double h(const A& a, int index)
{
    const auto bytes = std::bit_cast<std::array<std::byte, sizeof(A)>>(a);
    const auto offset = index * sizeof(double);
    std::array<std::byte, sizeof(double)> target;
    std::copy_n(bytes.begin() + offset, sizeof(double), target.begin());
    return std::bit_cast<double>(target);
}

static_assert([] {
    A a{};
    if (h(a, 0) != 1) return false;
    if (h(a, 1) != 2) return false;
    return true;
}());

// non-constexpr so that I can see the generated assembly
double f(const A& a, int index) {
    return h(a, index);
}
```

Above example is a reproducer for the problem which I faced in a large project,
which was accessing members of a class using an enum where:
- Enums were defined with X-macros.
- Class member names are defined with X-macros.
- Class member types were dependent on enum name where we select among multiple
wrappers of "double" -> B and C in above.
- Size of class = number of X-macro/enum entries * sizeof(double).
- All members are public.

Now the problem is that I wrote UB-free code using std::bit_cast (above) but
the generated assembly is not optimizing away the unnecessary copies. Whereas,
writing the following code is generating optimal assembly but is not UB-free
(static_assert fails): https://godbolt.org/z/hKEqE5zsY

```
constexpr double h(const A& a, int index)
{
    const double* address = &a.b.value;
    return *(address + index);
}
```

Am I missing something due to which bit_cast copies are not properly optimized
away here? I am not even doing unaligned accesses here.

Reply via email to