<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/136764>136764</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [[no_unique_address]] Zero sized subobjects don't overlap with any preceding sub-objects
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          Ext3h
      </td>
    </tr>
</table>

<pre>
    Consider the following example:

```c++
#include <cstddef>
#include <cstdint>

struct S1 {};

struct ST1 {
    [[no_unique_address]] S1 s1;
 [[no_unique_address]] S1 s2;
    [[no_unique_address]] S1 s3;
 [[no_unique_address]] S1 s4;
    [[no_unique_address]] S1 s5;
 [[no_unique_address]] S1 s6;
    uint16_t i1;
    uint16_t i2;
 uint16_t i3;
};

struct ST2 {
    uint16_t i1;
    uint16_t i2;
 uint16_t i3;
    [[no_unique_address]] S1 s1;
    [[no_unique_address]] S1 s2;
    [[no_unique_address]] S1 s3;
    [[no_unique_address]] S1 s4;
 [[no_unique_address]] S1 s5;
    [[no_unique_address]] S1 s6;
};


size_t size_st1() {
    return sizeof(ST1);
}

size_t offset_st1() {
    return offsetof(ST1, s2);
}

size_t size_st2() {
 return sizeof(ST2);
}

size_t offset_st2_i3() {
    return offsetof(ST2, i3);
}

size_t offset_st2_s1() {
    return offsetof(ST2, s1);
}

size_t offset_st2_s2() {
    return offsetof(ST2, s2);
}
size_t offset_st2_s3() {
    return offsetof(ST2, s3);
}

size_t offset_st2_s4() {
    return offsetof(ST2, s4);
}
```

With the following output: https://godbolt.org/z/TzTWb8xxc

The case `ST1` behaves as expected, all the zero-sized sub-objects are placed at contiguous memory addresses starting from offset 0. Finally `ST1::i1` to `ST1::i3` are also placed at contiguous memory addresses starting from 0, overlapping all of `ST1::s1` to `ST1::s6`. As a result `sizeof(ST1) == 6` holds as expected.

For `ST2` however the behavior is weird - `ST2::s1` has an offset of `0` as expected, but `ST2::s2` is the placed at the first address ***after*** `ST1::i3`. Resulting at the perfectly legal offsets 1-5 remaining unused, and `ST2` becomes much larger than expected: `sizeof(ST2) == 12`

It appears that if a struct already has any members that are not partially overlapping sub-objects, then Clang is unexpectedly not re-assigning addresses from this memory range despite being allowed to do so.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJycVk2P4jgQ_TXmUgI5Dglw4EA3g7TXnZZG2gty4grxysRZl9M0_etXdsLn9OzCSJYQduXVq1cvFUsivWsQlyx7Ydl6JDtfW7f89uHTelRYdVy-2oa0Qge-RqisMfagmx3gh9y3Blm6YjyunPerZOIlLL5iItVNaTqFwNLXkrxSWLH025dHuvHDEV-Rd13p4XsCbPbCZmuWvtwevPUnfAUAEJm_NHbbNfqfDrdSKYdELFuzbB1AKOkBHogUQ-RDsOnDsNNnYLOHYfMLbKcbn-RbDzr5avNU12VnIP-luuJK3d8Ffq4zDwX_VnMeCp4-LHn2DGz-s8ZBZv2JWw_xh3zCxJyJxZXiDn3nmnhuKybm398SJhYXqGsQW1WE_r9g-ogL0GvQ8VdwAydxC_YzoV8jnAmJrU4f4iQCpxD7_4j0WJURkR4QTWxJPIF4X_UXcE-UTI-VPH0CcXqPeJrJPfoP7eu7KW4733aepSuovW8pTHOxYWKzs6qwxk-s2zGx-WRi8_b59qOYf3yUPdZbjVBKQmA5D77KORRYy3ckkAT40WLpUQVW0piY9BOdHYcCFVBXjG3xN5aeQDqE1sgSFUgPpW283nW2I9jj3rojDG8VEpCXzgfSlbP7oXzgE9joRhpzPDFJVyxd6cjI29vNNGyGhNKQ_a2sPFRk39EZ2bZhN1Rnq5s09FVuylnOJ7AikOCQOuPD8d07Dixds3QNIRZqa9SNmJNe-Y11PbLoow74PnycYwO0daAJDqidgvEp8opYLQnkyT4Ddx6Fue1b0fnbp2M-TTHVRbvoJ-3InzQDJlb9kpVHd_73cysm8GdUIurYI7XoKiy9OYLBnTQDS4JknIHDvdRNCO6ajgZzNepKjAJLu0eCfVfWYKTbRWFkc6krXd3JLq5kT8T5VfnDg2xblC6UKz3oCiQM30dpHEp1HIQ8BssUeAoM7mqshza4Jtry2i1Xxg_sfY0NvBrZ7IKuXXOiaY4Rw-G4v55Fgc6OjEb0tT6b1clmh6CQWu2DCwZf2gOqYENlgexkpJapWqQLOcJlMptmaZalcz6ql-WsmKmsmnKRyrLiUvI5X_BFOc9klmCFI70UXGR8KoTgWS74RFTz-TyZcj6f8zzNFmzKQ2vMxJj3fRgZI03U4TJJ81k-HRlZoKF4wRSiwQPEUyZEuG-6ZXhoXHQ7YlNuNHm6wHjtzXAz_eV39i90Fs5j5TRVlG2YmPmT-HAIoy80q3VYorrrxahzZnk3ALWvu2JS2j0Tm0Bo-Bm3zoZnmNjEMoiJzVDn-1L8GwAA___dkXDK">