<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 3220: P0558 broke conforming C++14 uses of atomic shared_ptr</title>
<meta property="og:title" content="Issue 3220: P0558 broke conforming C++14 uses of atomic shared_ptr">
<meta property="og:description" content="C++ library issue. Status: New">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue3220.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#New">New</a> status.</em></p>
<h3 id="3220"><a href="lwg-active.html#3220">3220</a>. P0558 broke conforming C++14 uses of atomic <code>shared_ptr</code></h3>
<p><b>Section:</b> 32.5.2 <a href="https://wg21.link/atomics.syn">[atomics.syn]</a> <b>Status:</b> <a href="lwg-active.html#New">New</a>
 <b>Submitter:</b> Casey Carter <b>Opened:</b> 2019-06-11 <b>Last modified:</b> 2020-09-06</p>
<p><b>Priority: </b>3
</p>
<p><b>View other</b> <a href="lwg-index-open.html#atomics.syn">active issues</a> in [atomics.syn].</p>
<p><b>View all other</b> <a href="lwg-index.html#atomics.syn">issues</a> in [atomics.syn].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#New">New</a> status.</p>
<p><b>Discussion:</b></p>
<p>
This well-formed C++14 program:
</p>
<blockquote><pre>
#include &lt;atomic&gt;
#include &lt;memory&gt;

struct Abstract { virtual void test() = 0; };
struct Concrete : Abstract { virtual void test() override {} };

int main() {
  std::shared_ptr&lt;Abstract&gt; ptr;
  std::atomic_store&lt;Abstract&gt;(&amp;ptr, std::make_shared&lt;Concrete&gt;());
}
</pre></blockquote>
<p>
is ill-formed in C++17. <a href="https://wg21.link/p0558">P0558</a> changed the non-member
non-<code>shared_ptr</code> atomic functions to avoid deducing from their second argument,
e.g. C++14 <code>atomic_store</code>:
</p>
<blockquote><pre>
template&lt;class T&gt; void atomic_store(atomic&lt;T&gt;*, T); <i>// #1</i>
</pre></blockquote>
<p>
became C++17 <code>atomic_store</code>:
</p>
<blockquote><pre>
template&lt;class T&gt; void atomic_store(atomic&lt;T&gt;*, typename atomic&lt;T&gt;::value_type); <i>// #2</i>
</pre></blockquote>
<p>
The program intends to call the "other" <code>atomic_store</code> from
99 [depr.util.smartptr.shared.atomic]:
</p>
<blockquote><pre>
template&lt;class T&gt; void atomic_store(shared_ptr&lt;T&gt;*, shared_ptr&lt;T&gt;); <i>// #3</i>
</pre></blockquote>
<p>
In C++14, the call expression in the sample program &mdash;
<code>std::atomic_store&lt;Abstract&gt;(&amp;ptr, std::make_shared&lt;Concrete&gt;())</code> &mdash;
selects overload <code><i>#3</i></code>; overload <code><i>#1</i></code> fails to be viable due to the
lack of conversions from <code>shared_ptr&lt;Abstract&gt;*</code> to <code>atomic&lt;Abstract&gt;*</code>
and from <code>shared_ptr&lt;Concrete&gt;</code> to <code>Abstract</code>. In C++17, overload
<code><i>#2</i></code> doesn't get to the point of considering argument conversions: when we try to
generate the declaration of the specialization for <code>T = Abstract</code> we must instantiate
<code>atomic&lt;Abstract&gt;</code> in order to substitute <code>typename atomic&lt;Abstract&gt;::value_type</code>,
but doing so violates the requirement in [atomics.types.generic] p1 that "The type of the template
argument <code>T</code> shall be trivially copyable"
<p/>
The fix is fairly straightforward since <code>atomic&lt;T&gt;::value_type</code> is always an alias
for <code>T</code>: for those non-member atomic functions with overloads defined in
99 [depr.util.smartptr.shared.atomic], use a different form to require that <code>T</code>
in the type of the second parameter is non-deduced.
</p>

<p><i>[2019-07 Issue Prioritization]</i></p>

<p>Priority to 3 after discussion on the reflector.</p>


<p id="res-3220"><b>Proposed resolution:</b></p>
<p>This wording is relative to <a href="https://wg21.link/n4810">N4810</a>.</p>

<ol>
<li><p>Modify 32.5.2 <a href="https://wg21.link/atomics.syn">[atomics.syn]</a>, header <code>&lt;atomic&gt;</code> synopsis, as indicated:</p>

<blockquote><pre>
[&hellip;]
<i>// 32.5.9 <a href="https://wg21.link/atomics.nonmembers">[atomics.nonmembers]</a>, non-member functions</i>
[&hellip;]
template&lt;class T&gt;
  void atomic_store(volatile atomic&lt;T&gt;*, <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>) noexcept;
template&lt;class T&gt;
  void atomic_store(atomic&lt;T&gt;*, <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>) noexcept;
template&lt;class T&gt;
  void atomic_store_explicit(volatile atomic&lt;T&gt;*, <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>,
                             memory_order) noexcept;
template&lt;class T&gt;
  void atomic_store_explicit(atomic&lt;T&gt;*, <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>,
                             memory_order) noexcept;
[&hellip;]
template&lt;class T&gt;
  T atomic_exchange(volatile atomic&lt;T&gt;*, <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>) noexcept;
template&lt;class T&gt;
  T atomic_exchange(atomic&lt;T&gt;*, <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>) noexcept;
template&lt;class T&gt;
  T atomic_exchange_explicit(volatile atomic&lt;T&gt;*, <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>,
                             memory_order) noexcept;
template&lt;class T&gt;
  T atomic_exchange_explicit(atomic&lt;T&gt;*, <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>,
                             memory_order) noexcept;
template&lt;class T&gt;
  bool atomic_compare_exchange_weak(volatile atomic&lt;T&gt;*,
                                    <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>*,
                                    <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>) noexcept;
template&lt;class T&gt;
  bool atomic_compare_exchange_weak(atomic&lt;T&gt;*,
                                    <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>*,
                                    <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>) noexcept;
template&lt;class T&gt;
  bool atomic_compare_exchange_strong(volatile atomic&lt;T&gt;*,
                                      <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>*,
                                      <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>) noexcept;
template&lt;class T&gt;
  bool atomic_compare_exchange_strong(atomic&lt;T&gt;*,
                                      <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>*,
                                      <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>) noexcept;
template&lt;class T&gt;
  bool atomic_compare_exchange_weak_explicit(volatile atomic&lt;T&gt;*,
                                             <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>*,
                                             <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>,
                                             memory_order, memory_order) noexcept;
template&lt;class T&gt;
  bool atomic_compare_exchange_weak_explicit(atomic&lt;T&gt;*,
                                             <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>*,
                                             <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>,
                                             memory_order, memory_order) noexcept;
template&lt;class T&gt;
  bool atomic_compare_exchange_strong_explicit(volatile atomic&lt;T&gt;*,
                                               <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>*,
                                               <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>,
                                               memory_order, memory_order) noexcept;
template&lt;class T&gt;
  bool atomic_compare_exchange_strong_explicit(atomic&lt;T&gt;*,
                                               <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>*,
                                               <del>typename atomic&lt;T&gt;::value_type</del><ins>type_identity_t&lt;T&gt;</ins>,
                                               memory_order, memory_order) noexcept;
</pre></blockquote>

</li>

<li><p>Modify 32.5.9 <a href="https://wg21.link/atomics.nonmembers">[atomics.nonmembers]</a> as indicated:</p>

<blockquote>
<p>
-1- A non-member function template whose name matches the pattern <code>atomic_<i>f</i></code> or the
pattern <code>atomic_<i>f</i>_explicit</code> invokes the member function <code><i>f</i></code>, with the
value of the first parameter as the object expression and the values of the remaining parameters
(if any) as the arguments of the member function call, in order. An argument for a parameter of
type <code>atomic&lt;T&gt;::value_type*</code> <ins>or <code>type_identity_t&lt;T&gt;*</code></ins> is
dereferenced when passed to the member function call. If no such member function exists, the
program is ill-formed.
</p>
</blockquote>

</li>
</ol>




</body>
</html>
