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

    <tr>
        <th>Summary</th>
        <td>
            Clang and GCC differ in instantiation strategy of constexpr and incomplete types
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            c++20
      </td>
    </tr>

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

    <tr>
      <th>Reporter</th>
      <td>
          ilya-biryukov
      </td>
    </tr>
</table>

<pre>
    Consider this code compiled in C++20 mode:
```cpp
#include <vector>

struct X{
    struct Inner;
    unsigned size() { return children.size(); }
    std::vector<Inner> children;
};

struct X::Inner {
    int a;
};
```
MSVC and GCC will succeed, but Clang (trunk, wip version 16 at the time of writing) [produces an error](https://gcc.godbolt.org/z/jY4coE9aq):
```
/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/stl_vector.h:988:50: error: arithmetic on a pointer to an incomplete type 'X::Inner'
      { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
```

This boils down to different approaches when instantiating `constexpr` functions:
```cpp
template <class T>
struct vector {
 T* ptr;
    constexpr unsigned size() { return ptr - ptr; }
};

struct X{
    struct Inner;
    unsigned size() { return children.size(); }
    vector<Inner> children;
};

struct X::Inner {
    int a;
};
```
Clang instantiates the bodies of `constexpr` functions eagerly, other compilers seem to delay instantiation until the end of the TU, e.g. this code [fails](https://gcc.godbolt.org/z/cfTbdGhbd) in all compilers:
```cpp
template <class T>
struct vector {
    T* ptr;
    constexpr unsigned size() { return ptr - ptr; }
};

struct X{
    struct Inner;
    static constexpr int a = vector<Inner>().size();
    vector<Inner> children;
};

struct X::Inner {
    int a;
};
```

We have observed that this pattern is used in much of the existing code and I believe Clang should follow the GCC's and MSVC's approach here, even thought it is not mandated by the standard:
- it avoids breaking code that worked in C++17 when migrating to C++20.
- it allows to compile future C++20 code written for GCC and MSVC with Clang with no changes.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzMVkuT4jYQ_jXi0oXLlsHAgQMww9Ye9pTJ60TJUmNrR5YcqQ3D_vqUbJ6zu0kOqWSrKGFL7lY_vq-7RQi6sohLNl2z6dNIdFQ7v9TmJMal9qfu1R1GpVOn5cbZoBV6oFoHkE4hSNe02qACbWHD-JrxNU-hcQpZvmLpE0tXrEiHn2zb8w7PtZWmUwgs3xxQkvMsfz4f9msg30mC39hsPWwAAJw3P1qLnuV3B53tXVAQ9BdkfM74AthsDR6p8xZkrY3yaJPbMcvXwGZP97pVtDhfXczZnK95vopfr4yC1-dHc3sVvSQ8mK4tgfi2gkt4htdPP_2yAWEVfNhs4KiNgdBJiagY30DZEWyMsBUwPiff2de4e9QtHNAH7SxkBQgCqhFINwhuD0evSduqD8l03XqnOokBhAX03nk2fWJ8XhO1IRrPt4xvKymTyqnSGUqcrxjffmF8-_n3iXTPC_FHH773yb1kdmt0OahgfPs2L3bFZGy07d7Gle0Y32Z5kiYp49sk-Xo5o4LxrRywdC9QagqMbwOZ3ZCjpGb5ajGfs3w1TVm-OjuUr0B4TXWDpCU4CwJapy1F3Lrot7YRtQYJgU4tAuOz-8QxPrvlDe5xFOGziyIx-rUOY5Y_7z7tdNOaZPdpt9dWhxrG8I2zQMLTe9y9D16_vkRulU6bAModbbRZ6f0ePUYIta13QtYY4FhjdCWQsKRFTDFEjjkbCN9az4oU9p2VpJ0Nf8FFwqY1gnomSiNCgJcrFc-oHqJ9h-cXxlfQ0iMHrzf_HRtb8jA-i9_F4vuc-q9KwP_M_IHYt4xi6HlcOqUxRCZ_N72AokJvTrEYOKrRX8qyDxAQmx5DaMTpHi_OQmdJm_4StCreEB9ffo5qMKmSuzLPpuu90Cb882oh9y-l-lCXKiZCWxDG3Kz6l_EI8ENCMpCIFehmRQ8FYPnT11AbbHpE5w-DzGH9FaEWBwRXBvQHVEB132p0gFYQobegA3RhGAaaTtYXSOGbDn2B6rEUm9tHKNFoPOC5nYXadUbB3hnjjr3Mh82G8Vnov449cXg5lz-o0WMP0wNaoNp1VU2gKRpgHUEjrBKECspTryyCXgmvrrgbx4_FwWkVoPQoXq_W9U4dnX99mGmy2VBvG135odaSu807yb3S6EGIx2e0w76jzuPddNTfE9syoYW9832rv_gJR031OSr9o3Uga2ErDMlILXO1yBdihMusmOXTPMsW2ahe7vlMzqdyP5su-KRMi0Igz_J5OpUTTItpNtJLnvI8zTKe5ZMizxI145O5kDifiTwtRM4mKTZCm8SYQxNpPNIhdLicLhZFMTKiRBP6AZFzeXGEcR7nRb-MMuOyqwKbpEYHCjctpMngcnDnMtUM7SxG97EcBfKCsDpF2NxIE6Xedeww6rxZvqtCmuquTKRr4gxiDpe_cevdZ5QUp4voURwheqf-DAAA__-rzVLb">