<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/113530>113530</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[Clang] Accessing a reference member of a volatile-qualified class glvalue is misinterpreted as volatile read
</td>
</tr>
<tr>
<th>Labels</th>
<td>
clang:frontend,
constexpr
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
frederick-vs-ja
</td>
</tr>
</table>
<pre>
Currently, Clang (and GCC) rejects the following example ([link](https://godbolt.org/z/v9fKKEaGW)), which doesn't seem conforming.
```C++
struct S { const int& ref; };
constexpr int n = 42;
template<class T>
constexpr int readref(T&& t) {
return static_cast<T&&>(t).ref;
}
static_assert(::readref(static_cast<volatile S&&>(S{n})) == 42, "");
```
Error messages:
```
<source>:9:15: error: static assertion expression is not an integral constant expression
9 | static_assert(::readref(static_cast<volatile S&&>(S{n})) == 42, "");
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:6:30: note: read of volatile temporary is not allowed in a constant expression
6 | return static_cast<T&&>(t).ref;
| ^
<source>:9:15: note: in call to 'readref<volatile S>(S{n})'
9 | static_assert(::readref(static_cast<volatile S&&>(S{n})) == 42, "");
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:9:51: note: volatile temporary created here
9 | static_assert(::readref(static_cast<volatile S&&>(S{n})) == 42, "");
| ^
1 error generated.
Compiler returned: 1
```
I think the relevant standard wording is [[expr.const]/5.9](https://eel.is/c++draft/expr.const#5.9):
> an lvalue-to-rvalue conversion unless it is applied to
> - a non-volatile glvalue that refers to an object that is usable in constant expressions, or
> - a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of _E_;
However, there doesn't seem any wording treating evaluating a reference non-static data member of a class object as lvalue-to-rvalue conversion. So perhaps this example should be well-formed.
(A reference member behaves like it were an "auto-dereferencing" pointer in many cases. But IIUC this example is not such a case.)
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzUVs2SozYQfhr50mWXLYwxBx8wHm-29jibynFLQAPaERKRhL2TQ5491QL_zOxkks0hlVCUTYG6--uvf4VzstGIOxbvWXyYicG3xu5qixVaWT7NT27-VcwKUz3v8sFa1F49M55DroRugPGt0BV8yHPGU7D4FUvvwLcItVHKnKVuAL-JrldIZ1m8V1I_sfjA-Lb1vncsyhg_Mn5sTFUY5RfGNowff2P8eErrT58exIdfGE_DncO5lWULlUGnGU88OMQOSqNrYzupmwVbHtgym343y_HOGd_THd46b4fSwyOwZE-SzoPUnvENWKxZtAeWHFg0HQ7f8Vtv6QxoYNEB1vz6efz12PVKeGRRXirhHHxm0cNb8hZFRUb49jPjGzLpiTSWTOoALPrBanBeeFl-KYXzLMqnw6SUb0liMSKdMCSHezCTqHAOrSfCo4xF2c3yS9Uno4SXCuHx3sYjS_aa9AbayenJb54D4zzc6Q3AheZ7GA_WGgsdOicaDDF-82yUOzPYEslulKUsylYxizJAEqeHES6M7kijgchE5-hROtDGg9BELjZWqDGeQvu7YxdqAYjpHP59goJZFj_8_mPXmxRtWJRFS2JGG8q4LCQVmBquSCkdjRX2-UoQ1SFWIDWI9xnaBKj_IAkhXJOffxHbC3CpoRRKgTfAeHIJwAvKvyc7-R-G80_5iFf3fLwRwNKi8FhBixb_I47_-HXNiNVY1tCgRkt-Td06N10vFdop8bAiNlbvNJeP4Fupn8KUsajwRPlMWV0JW8HZ2IqmjnQQRtqeMn0R8j6MnWO8SN-aP4hqIR3jx3IcF5UVtaf3N3EekSxRkr0YNNEDdSF1EmrAuTdzG56o1k5oQ68atELnQHqCJfpeSazAm5v8HARoo-fXQDWjOvCtoMlRo3VUKkKDKWjIjh-kg8GJQmEop-9r21Eojf0bdkwNSnqkLuqf--_tvpSaMJxb4xCUrNHLDqHARmg4SwpPiA6SbhEat6nhy8OXV6PzJ3PGE1oC6SnJX092oZ-v8fRUDGGdmJTqBsSIEHWJAd80LirhBXTYFWjJroBxLk-ghXsvVAt4NNCjbUVPe4x01_XFtWZQFRQIZ1RqTivHNYcZ32Z3WCbbBbbihA6UfEKK_ZlcFJpqSwzezCu8iEjdMM6hNzTKaFuAjnwvhUO3gP3g4ePHn_OXeKb27oayJReFwwXj6azaRVUapWKGu1XC0yTmyWY7a3dJVEarbbQu6nidlljgaoNFzLdpiWVVr3Emd3zJ16slXy83MV9vF5ttimWaxkKsMcHNhq2X2AmpFkqdOtrTZtK5AXerVRRHy5kSBSoX9kjOS9oOWZTV1miPugq9JKcPl5WI3sSHmd2RtnkxNI6tl0o67276vfQqbKZh2WTxAbKypMx-Ffv7WF9ydP7rIJSsqdDG8F8yXTropAtE9xapvwp3677UQWeDVbtX26n07VAsStMxfiR809-8t4ayivFjIIMayMTHacf_CAAA___laYtH">