<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Erroneous behaviour for missing return from assignment</title>
    <style type="text/css">
      html { margin: 0; padding: 0; color: black; background-color: white; }
      body { margin: 0 auto; padding: 2em; font-size: medium; font-family: "DejaVu Serif", serif; line-height: 150%; max-width: 60em; }
      code { font-family: "DejaVu Sans Mono", monospace; color: #006; }

      h1, h2, h3 { margin: 1.5em 0 .75em 0; line-height: 125%; }
      h1 { clear: both; }

      div.code { white-space: pre-line; font-family: "DejaVu Sans Mono", monospace;
                 border: thin solid #E0E0E0; background-color: #F8F8F8; padding: 1em;
                 border-radius: 4px; }

      div.strictpre { white-space: pre; }

      sub, sup { margin: 0; padding: 0; line-height: 100%; }

      table { border-collapse: collapse; margin: 2em auto; }
      table caption { margin: 2ex 0 0 0; caption-side: bottom; font-family: "DejaVu Sans", sans-serif; font-size: small; }

      th, td { text-align: left; vertical-align: top; padding: .5ex 1em; margin: 0; }

      td.new { background-color: #EFE; }
      td.new:after { content: "new!"; font-family: "DejaVu Sans", sans-serif; font-weight: bold; font-size: xx-small;
                     vertical-align: top; top: -1em; right: -1em; position: relative; float: right; color: #090; }

      thead th { border-top: 2px solid #333; border-bottom: 2px solid #333; }
      tbody tr:last-child th, tbody tr:last-child td, tbody tr th.last { border-bottom: 2px solid #333; }
      tbody.lined td, tr.line td { border-bottom: 1px solid #333; }

      .code .note { font-family: "DejaVu Sans", sans-serif; font-size: small; padding: 0; margin: 0; color: #333; }

      .docinfo { float: right }
      .docinfo p { margin: 0; text-align:right; }
      .docinfo address { font-style: normal; margin-bottom: 2em; }

      .quote { display: inline-block; clear: both; margin-left: 1ex;
                 border: thin solid #E0E0E0; background-color: #F8F8F8; padding: 1ex; }

      .modify { border-left: thick solid #999; border-right: thick solid #999; padding: 0 1em; }
      .insert { border-left: thick solid #0A0; border-right: thick solid #0A0; padding: 0 1em; }
      .insert h3, .insert h4, .insert p { text-decoration: underline; color: #0A0; }
      .comment { color: #456; }
      .inclassit { font-family: "DejaVu Serif", serif; font-style: italic; }
      .insinline { border-bottom: 2px solid #0A0; }

      ins { color: #090; }
      del { color: #A00; }
      ins code, del code, .insert code { color: inherit; }

      ul.wide li { margin-bottom: 1em; }
      ul.wide li div.code { padding: 0.25ex 1ex; margin: 1ex 0; }
    </style>
  </head>
  <body>
    <div class="docinfo">
      <p>ISO/IEC JTC1 SC22 WG21 P2973R0</p>
      <p>Date: 2023-09-15</p>
      <p>To: SG12, SG23, EWG, CWG</p>
      <address>
        Jonathan Wakely &lt;<a href="mailto:cxx@kayari.org">cxx@kayari.org</a>&gt;<br>
        Thomas K&ouml;ppe &lt;<a href="mailto:tkoeppe@google.com">tkoeppe@google.com</a>&gt;
      </address>
    </div>

    <h1>Erroneous behaviour for missing return from assignment</h1>

    <h2>Contents</h2>
    <!-- fgrep -e "<h2 id=" erroneous_assignment.html | sed -e 's/.*id="\(.*\)">\(.*\)<\/h2>/<li><a href="#\1">\2<\/a><\/li>/g' -->
    <ol>
      <li><a href="#history">Revision history</a></li>
      <li><a href="#summary">Summary</a></li>
      <li><a href="#motivation">Motivation</a></li>
      <li><a href="#questions">Design questions</a></li>
      <li><a href="#proposal">Proposal: flowing off an assignment operator is erroneous</a></li>
      <li><a href="#references">References</a></li>
    </ol>

    <h2 id="history">Revision history</h2>
    <ul>
      <li>P2973R0: This (initial) version.</li>
    </ul>

    <h2 id="summary">Summary</h2>

    <p>
      We propose to change the behaviour of flowing off the end of an overloaded assignment
      operator from undefined to erroneous, erroneously returning <code>*this</code>.
    </p>

    <h2 id="motivation">Motivation</h2>

    <p>
      Flowing off the end of an assignment operator overload is a common mistake
      (<a href="https://github.com/isocpp/CppCoreGuidelines/pull/2097/files">example</a>,
      <a href="https://gcc.gnu.org/git/?p=gcc.git;a=blobdiff;f=libstdc%2B%2B-v3/testsuite/23_containers/map/modifiers/insert_or_assign/1.cc;h=aaf5d8a888bea965ede350c4923b62c21c050bb2;hp=48c17ebc5ef35432f875c987f15c562b3bf645ef;hb=6ec3c9c841aea8b492aa2fc0db5d3c734b643725;hpb=32e37414af3e1e236a2c7400c9d7178ede77ce4d">exam</a>&bullet;<a href="https://gcc.gnu.org/git/?p=gcc.git;a=blobdiff;f=libstdc%2B%2B-v3/include/experimental/propagate_const;h=635d4ed39fcd9f2a5a7d01a796bb3ca33478df52;hp=5f32111fbba241105f7a581cb6bf0f41a3e94867;hb=f6cdfe826444e1a0b52b271588fbef5c2a4bac4d;hpb=e600f2198f7dcdbdad2d469a3d498f6dbafb4468">ple</a>,
      <a href="https://github.com/llvm/llvm-project/commit/8a5170e02a415ed85cf60daf8434308526d14f61">ex</a>&bullet;<a href="https://github.com/llvm/llvm-project/commit/04298f851b645fc798b922ec30df53af14c2423a">am</a>&bullet;<a href="https://github.com/llvm/llvm-project/commit/40e5968eefce58d16220722bca844cedfa8226ab">ple</a>,
      <a href="https://github.com/llvm/llvm-project/commit/03d5dd28251badc63a841a48a317a36f8d566b98">etc.</a>):
    </p>
    <div class="code">struct Foo {
      &nbsp; Foo&amp; operator=(const Foo&amp; rhs) {
      &nbsp; &nbsp; x = rhs.x;
      &nbsp; &nbsp; y = rhs.y;
      &nbsp; &nbsp; <span style="color:#A00">// error: forgot "return *this;"!</span>
      };
    </div>
    <p>
      In current C++ (unlike in C) it is undefined behaviour to call a function with
      non-<code>void</code> return type that flows off the end, regardless of whether
      the result of the function call is used ([stmt.return]).
    </p>
    <p>
      <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2795r3.html">P2795R3</a>
      proposes the definition of &ldquo;erroneous behaviour&rdquo; in C++, which is well-defined
      behaviour that is nonetheless an error. The paper lays out
      <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2795r3.html#bigpic">principles</a>
      by which one can evaluate whether any particular undefined behaviour could be changed to
      be erroneous. We believe that flowing off an assignment operator meets those criteria:
    </p>
    <ul>
      <li>Potential for harm: common optimisations can cause the execution of an assignment
        operator with missing return to &ldquo;continue executing&rdquo; unexpected code.</li>
      <li>Detectable: the lack of return should be detectable at translation time. Common
        compilers can already warn on this.</li>
      <li>Opt-out: the status quo can be reinstated by inserting <code>std::unreachable()</code>,
        e.g. in branches that are known to the user to not be executed.</li>
    </ul>
    <p>
      A word on the cost of the now-defined behaviour: compilers can currently optimise
      aggressively based on the occurrence of undefined behaviour; all such optimisations would
      no longer be allowed. Usually, the original program was meaningless anyway, but one could
      argue that there may exist complex cases where some parts of a function had undefined
      behaviour but were known not to be used, which would now be pessimised. In such cases, one
      can explicitly insert <code>std::unreachable()</code> to those parts to restore the
      original behaviour, and we would even consider this an overall improvement, since it makes
      the unusual control flow more obvious. There remains a standard argument that in a large
      project one may be including third-party code that cannot be modified and that is not
      being used, but if that code contains the error under discussion, then with the proposed
      change it will produce a more expensive program (e.g. one that is larger). We consider
      this cost acceptable.
    </p>

    <h2 id="questions">Design questions</h2>

    <p>There is one major design question that should be discussed: precisely which assignment
      operators do we want to change?</p>
    <ul>
      <li>Only to special members, that is, overloads like <code>T& T::operator=(const T&amp;)</code>,
        <code>T& T::operator=(T&amp;&amp;)</code>, but see [class.copy.assign] for the full specification.
        This is a small, conservative change.
      </li>
      <li>Any assignment operator that returns a reference-to-self, like <code>T& T::operator=(int n)</code>,
        and regardless of ref-qualification. Such operators are common in &ldquo;fluent
        interfaces&rdquo;, and it is highly likely that <code>return *this;</code> was intended.</li>
      <li>Any assignment that returns something that is <em>convertible</em> to a reference-to-self.
        This would include <code>Base& Derived::operator=(/*...*/)</code>.
      </li>
      <li>Any assignment at all, regardless of return type (as long as the return type is
        not <code>void</code>).
        Unlike in the other alternatives, inserting an implicit <code>return *this;</code>
        would make some such functions ill-formed, where they compile correctly today
        (and have no undefined behaviour if control never actually flows off the end in the program).
        This seems hard to justify.</li>
    </ul>
    
    <h2 id="proposal">Proposal: flowing off an assignment operator is erroneous</h2>

    <p>
      We propose to change the semantics of flowing off the end of an assignment operator overload.
      The wording is relative to Working Draft <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4958.pdf">N4958</a>.
      The wording is a placeholder and implements only the most conservative design, only affecting special members.
    </p>
    <p>Modify [stmt.return, 8.7.4] paragraph 4 as follows:</p>
    <div class="modify">
      Flowing off the end of a constructor, a destructor, or a non-coroutine function
      with a <em>cv</em>&nbsp;<code>void</code> return type is equivalent to a <code>return</code> with no operand.
      <ins>Flowing off the end of a copy or move assignment operator ([class.copy.assign, 11.4.6])
      results in erroneous behaviour and is erroneously equivalent to a <code>return</code> with operand <code>*this;</code>.</ins>
      Otherwise, flowing off the end of a function
      that is neither <code>main</code> ([basic.start.main, 6.9.3.1])
      nor a coroutine ([dcl.fct.def.coroutine, 9.5.4]) results in undefined behavior.
    </div>

    <h2 id="references">References</h2>
    <ul>
      <li>Thomas K&ouml;ppe, <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2795r3.html">P2795R3</a>: <em>Erroneous behaviour for uninitialized reads</em></li>
      <li>Thomas K&ouml;ppe, <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4958.pdf">N4958</a>: <em>Working Draft, Programming Languages &mdash; C++</em></li>
    </ul>
  </body>
</html>
