<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
    "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
    "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg" xml:lang="en">
<head><meta http-equiv="Content-type" content="application/xhtml+xml;charset=utf-8" /><title>variant and optional should propagate copy/move triviality</title></head>
<body><!-- maruku -o trivially_variant.html trivially_variant.md --><style type='text/css'>
pre { margin: 0; }
pre code { display: block; margin-left: 2em; }
div { display: block; margin-left: 2em; }
ins { text-decoration: underline; background-color: #A0FFA0 }
del { text-decoration: line-through; background-color: #FFA0A0 }
</style><table><tbody>
<tr><th>Doc. no.:</th>	<td>P0602R3</td></tr>
<tr><th>Date:</th>	<td>2018-06-13</td></tr>
<tr><th>Audience:</th>	<td>Library Working Group</td></tr>
<tr><th>Reply-to:</th>	<td>Zhihao Yuan &lt;zy at miator dot net&gt;</td></tr>
</tbody></table>
<h1 id="variant_and_optional_should_propagate_copymove_triviality">variant and optional should propagate copy/move triviality</h1>

<h2 id="rationale">Rationale</h2>

<p>Making <code>variant</code> and <code>optional</code> conditionally trivially copy constructible, trivially move constructible, trivially copy assignable, and trivially move assignable significantly improves codegen and performance when they are nested or being put into containers.</p>

<p>Given the spirit of the resolution of <a href="http://cplusplus.github.io/LWG/lwg-defects.html#2900">LWG 2900</a> and feedback from implementers, this paper proposes a full-fledged approach shipped in libc<small>++</small>, MS STL, and libstdc<small>++</small> that is to make the four operations individually trivial if all alternatives have the corresponding operations being trivial.</p>

<p>This change comes with a (good) potential ABI breakage in user’s code – a small enough trivially copyable <code>optional</code> &amp; <code>variant</code> took or returned by a function can be passed via register after applying the change, therefore we propose to accept this change as a defect report against C<small>++</small>17.</p>

<h2 id="wording">Wording</h2>

<p>This wording is relative to N4750.</p>

<p>Modify 23.6.3.1 [optional.ctor] as follows:</p>

<pre><code>constexpr optional(const optional&amp; rhs);</code></pre>

<blockquote>
<p>[…]</p>

<p><em>Remarks:</em> This constructor shall be defined as deleted unless <code>is_copy_constructible_v&lt;T&gt;</code> is <code>true</code>. If <code>is_trivially_copy_constructible_v&lt;T&gt;</code> is <code>true</code>, this constructor <del>shall be a <code>constexpr</code> constructor</del><ins>is trivial</ins>.</p>
</blockquote>

<pre><code>constexpr optional(optional&amp;&amp; rhs) noexcept(see below );</code></pre>

<blockquote>
<p>[…]</p>

<p><em>Remarks:</em> The expression inside <code>noexcept</code> is equivalent to <code>is_nothrow_move_constructible_v&lt;T&gt;</code>. This constructor shall not participate in overload resolution unless <code>is_move_constructible_v&lt;T&gt;</code> is <code>true</code>. If <code>is_trivially_move_constructible_v&lt;T&gt;</code> is <code>true</code>, this constructor <del>shall be a <code>constexpr</code> constructor</del><ins>is trivial</ins>.</p>
</blockquote>

<p>Modify 23.6.3.3 [optional.assign] as follows:</p>

<pre><code>optional&lt;T&gt;&amp; operator=(const optional&amp; rhs);</code></pre>

<blockquote>
<p>[…]</p>

<p><em>Remarks:</em> If any exception is thrown, […]. This operator shall be defined as deleted unless <code>is_copy_constructible_v&lt;T&gt;</code> is <code>true</code> and <code>is_copy_assignable_v&lt;T&gt;</code> is <code>true</code>. <ins>If
<tt>is_trivially_copy_constructible_v&lt;T&gt; &amp;&amp; is_trivially_copy_assignable_v&lt;T&gt; &amp;&amp; is_trivially_destructible_v&lt;T&gt;</tt>
is <code>true</code>, this assignment operator is trivial.</ins></p>
</blockquote>

<pre><code>optional&lt;T&gt;&amp; operator=(optional&amp;&amp; rhs) noexcept(see below );</code></pre>

<blockquote>
<p>[…]</p>

<p><em>Remarks:</em> The expression inside <code>noexcept</code> is equivalent to: […] This operator shall not participate in overload resolution unless <code>is_move_constructible_v&lt;T&gt;</code> is <code>true</code> and <code>is_move_assignable_v&lt;T&gt;</code> is <code>true</code>. <ins>If
<tt>is_trivially_move_constructible_v&lt;T&gt; &amp;&amp; is_trivially_move_assignable_v&lt;T&gt; &amp;&amp; is_trivially_destructible_v&lt;T&gt;</tt>
is <code>true</code>, this assignment operator is trivial.</ins></p>
</blockquote>

<p>Modify 23.7.3.1 [variant.ctor] as follows:</p>

<pre><code>variant(const variant&amp; w);</code></pre>

<blockquote>
<p>[…]</p>

<p><em>Remarks:</em> This constructor shall be defined as deleted unless <code>is_copy_constructible_v&lt;T</code><i><sub>i</sub></i><code>&gt;</code> is <code>true</code> for all <em>i</em>. <ins>If
<tt>is_trivially_copy_constructible_v&lt;T</tt><i><sub>i</sub></i><tt>&gt;</tt>
is <code>true</code> for all <em>i</em>, this constructor is trivial.</ins></p>
</blockquote>

<pre><code>variant(variant&amp;&amp; w) noexcept(see below );</code></pre>

<blockquote>
<p>[…]</p>

<p><em>Remarks:</em> The expression inside <code>noexcept</code> is equivalent to […]. This function shall not participate in overload resolution unless <code>is_move_constructible_v&lt;T</code><i><sub>i</sub></i><code>&gt;</code> is <code>true</code> for all <em>i</em>. <ins>If
<tt>is_trivially_move_constructible_v&lt;T</tt><i><sub>i</sub></i><tt>&gt;</tt>
is <code>true</code> for all <em>i</em>, this constructor is trivial.</ins></p>
</blockquote>

<p>Modify 23.7.3.3 [variant.assign] as follows:</p>

<pre><code>variant&amp; operator=(const variant&amp; rhs);</code></pre>

<blockquote>
<p>[…]</p>

<p><em>Remarks:</em> This operator shall be defined as deleted unless <code>is_copy_constructible_v&lt;T</code><i><sub>i</sub></i><code>&gt; &amp;&amp;</code> <code>is_copy_assignable_v&lt;T</code><i><sub>i</sub></i><code>&gt;</code> is <code>true</code> for all <em>i</em>. <ins>If
<tt>is_trivially_copy_constructible_v&lt;T</tt><i><sub>i</sub></i><tt>&gt; &amp;&amp; is_trivially_copy_assignable_v&lt;T</tt><i><sub>i</sub></i><tt>&gt; &amp;&amp; is_trivially_destructible_v&lt;T</tt><i><sub>i</sub></i><tt>&gt;</tt>
is <code>true</code> for all <em>i</em>, this assignment operator is trivial.</ins> […]</p>
</blockquote>

<pre><code>variant&amp; operator=(variant&amp;&amp; rhs) noexcept(see below );</code></pre>

<blockquote>
<p>[…]</p>

<p><em>Remarks:</em> This function shall not participate in overload resolution unless <code>is_move_constructible_v&lt;T</code><i><sub>i</sub></i><code>&gt; &amp;&amp;</code> <code>is_move_assignable_v&lt;T</code><i><sub>i</sub></i><code>&gt;</code> is <code>true</code> for all <em>i</em>. <ins>If
<tt>is_trivially_move_constructible_v&lt;T</tt><i><sub>i</sub></i><tt>&gt; &amp;&amp; is_trivially_move_assignable_v&lt;T</tt><i><sub>i</sub></i><tt>&gt; &amp;&amp; is_trivially_destructible_v&lt;T</tt><i><sub>i</sub></i><tt>&gt;</tt>
is <code>true</code> for all <em>i</em>, this assignment operator is trivial.</ins> The expression inside <code>noexcept</code> is equivalent to: […]</p>
</blockquote>

<h2 id="acknowledgments">Acknowledgments</h2>

<p>Thanks Casey Carter for evolving the implementations and explaining the results.</p>
</body></html>
