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

    <tr>
        <th>Summary</th>
        <td>
            [[msvc::no_unique_address]] differs in layout from MSVC ABI
        </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 examples:

```c++
#include <cstddef>

struct S1 {};
struct S2 {};

struct S3 {
    [[no_unique_address]] [[msvc::no_unique_address]] S1 s1;
};

struct ST1 {
    [[no_unique_address]] [[msvc::no_unique_address]] S3 s1;
    S1 s2;
};

struct ST2 {
 [[no_unique_address]] [[msvc::no_unique_address]] S3 s1;
    S2 s2;
};

struct ST3 {
    [[no_unique_address]] [[msvc::no_unique_address]] S3 s1;
    [[no_unique_address]] [[msvc::no_unique_address]] S1 s2;
};

struct ST4 {
 [[no_unique_address]] [[msvc::no_unique_address]] S3 s1;
 [[no_unique_address]] [[msvc::no_unique_address]] S2 s2;
};

static_assert(sizeof(ST1) == 2);

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

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

#ifdef _MSC_VER
static_assert(sizeof(ST2) == 2);
#else
static_assert(sizeof(ST2) == 1);
#endif

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

size_t offset_st2() {
    return offsetof(ST2, s2);
}

#ifdef _MSC_VER
static_assert(sizeof(ST3) == 1);
#else
static_assert(sizeof(ST3) == 2);
#endif

size_t size_st3() {
 return sizeof(ST3);
}

size_t offset_st3() {
    return offsetof(ST3, s2);
}

static_assert(sizeof(ST4) == 1);

size_t size_st4() {
 return sizeof(ST4);
}

size_t offset_st4() {
    return offsetof(ST4, s2);
}
```

Example output: https://godbolt.org/z/xnrT5Tsq1

For `ST4` the behavior of Clang and MSVC matches in all aspects, both compilers optimize to the expected extent.

For `ST1` the layout does match, but actually not for the same reasons. MSVC preserves `ST1::s1` as a unique address because of the unique sibling `ST1::s2`. Clang preserves `ST1::s1` because otherwise `ST1::s2` would alias `ST1::s1::s1`. And actually the output of ***neither*** compiler is optimized as far as you'd expect.

This difference then causes trouble in `ST2`. Clang applies the optimization as strict aliasing rules are applied, but MSVC doesn't.

In `ST3` we can see the opposite behavior. Even though everything is flagged with `[[msvc::no_unique_address]]`, Clang still tries to avoid aliasing of `ST1::s2` and `ST1::s1::s1`. MSVC does not.

See also https://github.com/microsoft/STL/issues/1364 for the epic depending on ABI equality.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJy0V0tv4joU_jVmczQosRNKFyyAFmmkO5tLNdvKiU-Ir4yd8XHo49dfOQmlD16LjmQpAtvf6yTHiSTSG4s4Y_mC5Xcj2Yba-dn9cxD1qHDqZbZ0lrRCD6FGqJwx7knbDeCz3DYGiYk5S7oxSfpRMr6II5kzLrQtTasQmFiWFJTCion7fgMF35YB1imwmwW7uWNi8e5f_uHfdxOim0jmAACd6IV1j63Vf1p8lEp5JGL5Hcvvhtkt7cooUsxPrVunQOnAc4TwIf1-RvHGGEGjAH5GAN8L-Dvs_Dz7Xwj8o4Dvq-I5G9nfC_GbEE_VQQZdPkoi9IHxKelXdBXj0_VDyvgtMHHHxB1wxm8Pe_QrPgboLhRSxqfdyt6_x9B6C59wDsTvEVxVEYavGAB7mH7FAWgZTXyBi52gUljB46_18vH3_b_njfHjxrhAQ3j91vTDVqt0dSwefimeI34-x8Oviod_UzzipMeL8YiTyZ6KR1yKR1yOR1wVjzgVzxk_2fEoPpvILpnILpvIrjKRHTexPxx76Pv-8ATXhqYNTMyhDqHpzlK-Yny1capwJoyd3zC-emV89Wz9Q_5Af9IeYOU8sEkS6SZJdzIXWMuddh5cBUsj7QakVfBr_XsJWxnKGgm0BWkMSGqwDBR1Fi7UULptow16AtcEvdWvCMF1mPgcV6ICfA5ow_gTd7rnNvLFtQGUQ-rJOuw2gCxDK415AesCVK5_hyC5RfAoyVka9wobj4R-h7QH7holdQSSQELfMGFomFBgKVvC6DUiDrOkCxNfTT5gcDZJxkMi52jeIEON_kkTfoWBJ9caBdJo-QXhgDSGuVUH51FfX-aolvF5PyzqSPT2-60KoA91UNF8JX28vLiW8Rs11GQoxUOtCZSuKvRoS4xkFjofBMG7tjAYq95pfR-EbBqj45oorieTQTsbiSh4XYbeZUzTtwYJpMdhl9oXt6tcrLll_Gav6OfAJrq8EEppgRAHpsaRDod7dQz3O7QQatduasAd-pdQR05NUBm52aCCJx3qCHnlKRpX8uVgk4I2BoLvrDqQO6fVwVgsx5cSx4fmTGnfPMc7erC8RgRpyH1-hnWo22Jcui3jq60uvSNXBcZX64d_GF9pohaJ8VUqJtnbs4GNLkFhE7txlGhhvvgJ-KeVRoeX8UjNhLoVt3KEs_QmywVP8tt0VM-SYooqV0nJJRZFeSPEhN-maTEVlRAiLUd6xhOeJxnnaZpORDrOpjmPqycyT5IKFcsS3EptxsbstrHxjDqFs1RMJtN8ZGSBhrqvBM4tPkE3yziPHw1-Fjf9KNoNsSwxmgIdYIIOZvi8uOIlqL-Zu141dJXKu22f-3zxc9R6MzuTc2QdLj8a7_7DMnzKOprZzfj_AQAA___qQ-q7">