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

    <tr>
        <th>Summary</th>
        <td>
            constexpr pointer member with non-constexpr out-of-class definition not allowed in a constant expression
        </td>
    </tr>

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

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

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

<pre>
    Consider the following code, reduced from Boost.Asio:
```cpp
struct tracked_t {
  static constexpr void *static_query_v = 0;
};
void * const tracked_t::static_query_v;
static constexpr auto r = tracked_t::static_query_v;
```

A `constexpr` variable can have a non-`constexpr` declaration. Additionally, prior to C++17 the in-class declaration here is not a definition, and the definition itself is out-of-class. (C++17 changed this, see appendix D.1 `[depr.static_constexpr]`.)

In C++11 or C++14 mode, Clang gives
```
x.cpp:6:23: error: constexpr variable 'r' must be initialized by a constant expression
static constexpr auto r = tracked_t::static_query_v;
                      ^   ~~~~~~~~~~~~~~~~~~~~~~~~~
x.cpp:6:27: note: read of non-constexpr variable 'static_query_v' is not allowed in a constant expression
static constexpr auto r = tracked_t::static_query_v;
                          ^
x.cpp:5:25: note: declared here
void * const tracked_t::static_query_v;
                        ^
1 error generated.
```
on this sample. This is because Clang looks at the definition of `static_query_v`, which is out-of-class and does not have the `constexpr` specifier, even though the variable itself is `constexpr`.

The relevant code is here: https://github.com/llvm/llvm-project/blob/b73d2c8c720a8c8e6e73b11be4e27afa6cb75bdf/clang/lib/AST/ExprConstant.cpp#L4054-L4058 It retrieves the definition, if one is available, and later checks `VD->isConstexpr()` on it.

Note that the same sample, but with `int` instead of a pointer type is accepted, because the code takes the `BaseType->isIntegralOrEnumerationType()` branch later.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzFVU1v4zYQ_TXyhbAgU7YlH3Rw7CwQoGgPDXoNKGpkc0OTKkk5cX99Zyj5I94Au0UXWEOWSFHzZubxzbC2zanaWONVA46FPbDWam3flNkxaRtI-IY5aHoJDWudPbAHa31I117ZJF8n2TbJ1skyGy7ZdcMbH1wvAwtOyFdoXgJLiodhhTEfRFASwY0P8N45drSqYQlfDwsvf_fgTi9HluRbliX5aJcU28v4bDBgXL1QQPkdzMXoG7eiD5a56ObHEC5pjtN4XzPK-wyKY3YUTolaA5PCsL04AhPMWDO9_64BqYVDT9akbN00ikZC6xNR3jllcTss2yT8Aa9ZEfdGmSkaeX9rzPbgcMWjk4CuGmiViViEI0wTDa9vmQoedEsGtg9T2w6IKRJaXp3JvTA7IFvlCccDptF1YBr1zrbpjLJOFg8NdC4d6bomt9jiaprw1S1RT-aSy4xhbufJnB1GmW00-mQ7dQT_KeHvKekrXy_xz3O8MXDOOhrciOnMfsILh3926FEiNVGH6Qut_sGs6hMSFW2ECYzswHti7CcphX36SxaPdC8ef9r1LS0FsYFCAHo6EA2zbVTf5wzdxY90nXVEPQCZUuZXMDWy9TG_BeW3uM1vKAKMkirgf7SG74YwG5TGdmAAiw6a9FOBYnFRvTAvDp2GlD3TBK8apOg9jALX1r56JsJ9XeJGIdJdiAiNlfG2V3J_X7GxthsLw4bFRkOI923GdyBVq8AREByBYrT9bh8_vmjh2hTu7NPbGn5GEwcajiQGOh3IIJKPu7EPofPEM_-C106FfV-n0h5wovXx_Jh2zn4FGXBaa1vTo8gbLktZ8EyUsoQlFHk9m9UwB16IVixlXSzqpsVPJRFIQIoM138-4_0R49yMAo1K4flv82wxn9K9ZE8BIw5OYeb-jnEiRLXMmpiGOAqliYtz29S40Q4bIcjXyMpf22mSPyq_ubDDS-pxyHHsqh-Y-h0liu7GXUZBwKgKQq_7wN6QH0JVJhCCIsyhWgXrLL6l0_jUDaFJCR2qLtqOWiLYuANBvI6ZIc6D8PCMVkOkT4iyc0L_4R5Nf4DhuKDla-S1EwalFXNNJ1DNlsu8zHmW80lT5c0qX4lJUEFDdS3yc3gHONT4iJl8bDEfZHoj8R_pLJPe6eo_a0l53-Oxwb8sinI1n-yr1bLOWpHNypzYazJUkyxKLlFiq0U2hwnuNWhf4SGWcG7gjUUIHOPxNVEVzzjPVvgv8nzBUzHPy0LIti7Ktl22kMwzOKBgUoojtW43cVUMqe53Hhe18sFfF5EHtTMA0R3iY5_cW1ehzBycjpPouoqh_wt92wnS">