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

    <tr>
        <th>Summary</th>
        <td>
            propagate_const should not be using SFINAE on its conversion operators
        </td>
    </tr>

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

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

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

<pre>
    This is a clone of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107525

---

`propagate_const` in the LFTSv3 has implicit conversion operators which have constraints on them:

https://cplusplus.github.io/fundamentals-ts/v3.html#propagate_const.const_observers

> `constexpr operator const element_type*() const;`

> Constraints:
>    `T` is an object pointer type or has an implicit conversion to `const element_type*` .
> Returns:
>    `get()`.



libstdc++ implements these constraints by means of SFINAE on the operators. This is user-hostile: using SFINAE means that the conversion operator is now a function template, and that means that https://eel.is/c++draft/over.ics.user#3 kicks in:

> If the user-defined conversion is specified by a specialization of a conversion function template, the second standard conversion sequence shall have exact match rank.


Concretely, this means that for instance we lose implicit conversions towards base classes of the pointed-to type:

```
    std::experimental::propagate_const<Derived *> ptr;

    Derived *d1 = ptr;  // Convert precisely to Derived *: OK
    Base *b1    = ptr;  // Convert to a pointer to a base: ERROR

    Base *b2    = static_cast<Derived *>(ptr); // OK
    Base *b3    = static_cast<Base *>(ptr);    // ERROR

    Base *b4    = ptr.get();  // OK
```

But these should all work. The design of propagate_const is for it to be "drop-in replacement", maximizing compatibility with existing code. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html says explictly

"When `T` is an object pointer type `operator value*` exists and allows implicit conversion to a pointer. **This avoids using `get` to access the pointer in contexts where it was unnecesary before addition of the propagate_const wrapper.**" (emph. mine)

---

The suggest workaround (that got implemented in libstdc++) is not to use SFINAE on the operator itself, but isolate them in base classes and use SFINAE on such classes instead.


</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJyNVlFv2zgM_jXOixAjsZvEechDuy7AcIcb0A24x0KWGVurYvksOV726--jnDROlh6ucB1LosmP5EfSuS2Om--VdgKXFMrYmoTdicr7xkXpY5RscZVKxWXdxbYtscq78pc2RuLRVbZ_xTpWpY7SrS6i9Hk-Wy2SRTR7jmaPw306nY6X0XLWtLaRpfT0qmztPHaEroWvSPy5_f7tkIpKAtG-MVppLyBzoNZpWwvbUCu9bZ3oK60qyB1IBB2t1LV3wgY1e4Y-MnntjmpM5_g_LrWvujzWFru7ri7knmovjZt6h51DGld-b6IkvcEbh_urzR21jOzKu_SzgD9Bgn427TvkAaYgQ2zk1R8bihIgyqJkPZxF6RPeHKl5f_p08fDiGfbxhze-h_ghf4hP_oOUF42FKLWCjQiY5nDi9F5EvX2H-xs2qI0vxl7Id219D0BJfvADz_FVMEZ3o3PnCxUlT7gClGDMcb7cdRLzo9iTrB0z8dv2y1-Pn095veQ_FmfWdkjCtLLOa0PAhrWuy_NrgxpfSR9ev8MkVlHbHuQHAZQPISGAQ7Kj5BOiVgyvjzRds4nIxJrpcnKtaOUO4dhaWIq1cjEDBIdS8abVGyDXN-TkOH7ZBXzBl4J2uqZiDBYYXUNK7zT2ER05LKXRv2SAjEDJ8Qt3fWELjiBVCOfhmGyvjDj6p6NaQaaSxgylRT8l6LSXHrXWyvrtTnbBTdWSJ3McbADrKFY7jnDN5qC4J2Escn2HhxC3PQAh-ZLZYKRzFAjAqAc-F1OQNXDzJoAomuEKSyYlmMZC6SNKkFo9lPWwc9t70k_PkDggsEx55KLxLVfiyABrHAkVc4E-d5JDAQQacI3CF9Rei8w4hINL60r1o_j6x0XhE_uJ_XwequhjhVAjLxXNCw4Rq_v88vL15Rbou97krBfR91q9KnnHW9Qtm0XpwvLJ8F2U6X1t5_NbVeLdjf8G-TByPr70kVEYzmhusjzcnzp_6h8YRZ0pBDO3t-0b9wcSBTldhuq4yTpXVKBmCG_OWJICIlOMoZZQMSo0J-wyqffyp97rX9xXlN038D_XRvuj6DE_UCMazSecFRTfdIe-72O0mnoKRp7m5w-v5jw7FSvf9mXCq8Iq7iGNbHieJNtkNl_gp35IsyxMIeHk0cEWV45HrY35nyR_V1T_j1GA0_e-d5CmO3f54IILzQ4BtP394TsmYhySnjyGLiwPVhfu1HlP8wBaWV4pcm5Uw9wNWCdmo-chTi1xEnoMqK6uCdKyPSIhSA4JWRT63N6Cipsk9q1s4E48QEEYACpDw6tisUcLZSJ9_BnC_HBdWRIrAmNka_EFwBpC4yqtvwwplAtgX00wntphdAQGoXF_MKngHZrBjmmUd8w7y-04fKSwzqtux_G_1uQ6NN7zMfdRksVVD57QZr5crhbZarZeTYpNWqzTtZx47Q1tbuN1qhHGnNP1oOQhg4Tc-9SadK3Z3HwQDt9NKAYsjDmcf6awyKzDUjvXETN5kWXzbFJt1rs1qSJN8gXtVotV-rBScpXNdtksy5bFQz4xMifjNtECsU1q6kVQwSW4eJ7oTTJLkvl89jDP0my-jIs1zbJCzZbQk6rlOnqY0V5qEzMOrrRJuwmQ8HnqcGiY4ZdDRBSdgSiYg37Z-cq2m0LWJRlbToLtTcD-L2b7kwQ">