<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <meta name="generator" content="pandoc" />
  <title>P1782R1: Local contract restrictions</title>
  <style type="text/css">code{white-space: pre;}</style>
  <style type="text/css">
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
  margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; }
code > span.dt { color: #902000; }
code > span.dv { color: #40a070; }
code > span.bn { color: #40a070; }
code > span.fl { color: #40a070; }
code > span.ch { color: #4070a0; }
code > span.st { color: #4070a0; }
code > span.co { color: #60a0b0; font-style: italic; }
code > span.ot { color: #007020; }
code > span.al { color: #ff0000; font-weight: bold; }
code > span.fu { color: #06287e; }
code > span.er { color: #ff0000; font-weight: bold; }
  </style>
  <style type="text/css">
  s, .del { background: #ff8888; }
  u, .ins { background: #88ff88; }
  /* from https://stackoverflow.com/a/32456613 */
  body > blockquote {
      display: list-item;
      list-style-type: "- ";
  }
  pre {
  		margin-left: 1.2em;
  }
  </style>
</head>
<body>
<div id="header">
<h1 class="title">P1782R1: Local contract restrictions<!-- -*- c++-md -*- --></h1>
</div>
<p><em>Audience</em>: SG21<br />S. Davis Herring &lt;<script type="text/javascript">
<!--
h='&#108;&#x61;&#110;&#108;&#46;&#x67;&#x6f;&#118;';a='&#64;';n='&#104;&#x65;&#114;&#114;&#x69;&#110;&#x67;';e=n+a+h;
document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'">'+e+'<\/'+'a'+'>');
// -->
</script><noscript>&#104;&#x65;&#114;&#114;&#x69;&#110;&#x67;&#32;&#x61;&#116;&#32;&#108;&#x61;&#110;&#108;&#32;&#100;&#x6f;&#116;&#32;&#x67;&#x6f;&#118;</noscript>&gt;<br />Los Alamos National Laboratory<br />July 31, 2019</p>
<h1 id="history">History</h1>
<p>r1:</p>
<ul>
<li>Made <code>static</code> conditions unevaluated operands</li>
<li>Replaced <code>halt</code> with <code>continue</code>; removed the global continuation mode</li>
<li>Explained behavior subset structure</li>
<li>Listed meaningful modifier combinations</li>
<li>Extended comparisons to other papers; removed erroneous claim about P1290R1’s <code>continue</code></li>
</ul>
<h1 id="introduction">Introduction</h1>
<p>Disagreement over the mechanisms for controlling contract evaluation and assumption led to removing the feature altogether for C++20; see my <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1494r0.html">P1494R0</a> as well as <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1490r0.html">P1490R0</a> for a review of some recent concerns involving optimization. Papers like <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1332r0.txt">P1332R0</a> (pared down as <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1429r2.pdf">P1429R2</a> and a bit further as <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1607r0.pdf">P1607R0</a>) have also proposed significant extensions to those mechanisms for the purposes of better control and scalability.</p>
<p>Fundamentally, a contract (that is, what N4820 called a <em>contract-attribute-specifier</em>) is a boolean expression whose evaluation and significance can be controlled non-locally (by, <em>e.g.</em>, the continuation mode). The common protocol (across many files of diverse authorship) for such control is the principal reason that that contracts exist as a language feature. The alternative, per-library approach is of course already available:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> my_lib {
  <span class="kw">struct</span> Stuff {<span class="co">/*...*/</span>};

  <span class="dt">bool</span> check_expensive(),keep_going();
  <span class="dt">bool</span> bad_news(<span class="dt">const</span> Stuff&amp;);

  <span class="dt">void</span> do_stuff(<span class="dt">const</span> Stuff &amp;s) {
    <span class="kw">if</span>(check_expensive() &amp;&amp; bad_news(s))
      <span class="kw">if</span>(keep_going()) std::fprintf(<span class="co">/*...*/</span>);
      <span class="kw">else</span> <span class="kw">throw</span> <span class="co">/*...*/</span>;
    s.do_it();
  }
}</code></pre>
<p>It is also worth noting that concerns about optimization and assumptions in particular are subject to the normal implementation-supplied control over such analyses (<code>-fno-assume-contracts</code> wouldn’t surprise anyone and would be implied by <code>-O0</code>). All that being said, the usability concerns that led to the feature’s deferral are very real.</p>
<p>The situation can be understood in terms of the four behaviors described in P1429R2. In any given build, a single contract must have exactly one of the four. For some contracts, all four behaviors are reasonable, and the choice is made by the global controls. For others, certain behaviors are unreasonable and should not be selected regardless of the general preference expressed via the global controls. Perhaps the best example is a contract just introduced into code already in use, where using it to drive optimization would be inappropriate even if other similar contracts are already being so utilized. Another is a contract introduced to prevent following undefined behavior (when checking can be afforded), where continuing past a violation would be nonsensical even if other contracts are being used for logging purposes. Unfortunately, the single local control on a contract (the level) is able to influence the choice of behavior in only a very limited fashion and does not address either of these examples.</p>
<p>This paper proposes replacing the N4820 <em>contract-level</em> with a set of <em>restrictions</em> that limit the effect of the global controls, to be applied when local conditions (including the recency of a contract’s introduction) make it unsafe to take full advantage of the consistent control. The local restrictions only reduce the set of behaviors available via the global controls for a construct; the only direct control (along the lines of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1334r0.txt">P1334R0</a>) provided is a guaranteed check. This proposal also stops well short of an extensible roles system as proposed by P1332R0.</p>
<p>Two simple changes are proposed to the global controls as well: the global continuation mode is replaced with a local control, and the <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1710r0.html">ever</a> <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1711r0.pdf">popular</a> <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1730r0.md">assumption mode</a> is added.</p>
<h1 id="proposal">Proposal</h1>
<p>Relative to N4820.</p>
<h2 id="global">Global</h2>
<p>Remove the violation continuation mode; except as noted below, call <code>std::terminate</code> if the violation handler returns. (The situation with the continuation mode <em>off</em> can of course typically be emulated by calling <code>std::terminate</code> from the violation handler.) Add a different global control, the <em>assumption mode</em>, that when <em>off</em> restricts contract condition evaluation to those that are guaranteed to be evaluated. That is, it suppresses the controversial passage from [dcl.attr.contract.check]/4:</p>
<blockquote>
<p>it is unspecified whether the predicate for a contract that is not checked under the current build level is evaluated; if the predicate of such a contract would evaluate to <code>false</code>, the behavior is undefined.</p>
</blockquote>
<h2 id="local">Local</h2>
<p>In the place where one of <code>default</code>, <code>audit</code>, or <code>axiom</code> may currently appear, instead allow a combination of the following modifiers with the given semantics:</p>
<table><tr>
<td style="width: 6em">
<code>tentative</code>
</td>
<td>
the expression may not be assumed if it is not evaluated; disallows <em>assume</em> behavior
</td>
</tr><tr>
<td>
<code>continue</code>
</td>
<td>
do not call <code>std::terminate</code> after calling the violation handler; replaces <em>enforce</em> behavior with <em>inform</em>
</td>
</tr><tr>
<td>
<code>static</code>
</td>
<td>
the expression is never evaluated and is an unevaluated operand; disallows <em>inform</em> and <em>enforce</em> behaviors
</td>
</tr><tr>
<td>
<code>audit</code>
</td>
<td>
the expression may not be evaluated if the build level is not <em>audit</em>; conditionally disallows <em>inform</em> and <em>enforce</em> behaviors
</td>
</tr><tr>
<td>
<code>always</code>
</td>
<td>
the expression is always evaluated at all build levels; disallows <em>ignore</em> and <em>assume</em> behaviors
</td>
</tr>
</table>

<p>A new contract may be introduced with the <code>tentative</code> restriction to avoid adding undefined behavior to existing interfaces. A contract without <code>continue</code> may be used to optimize the code that follows it if it is checked, regardless of <code>tentative</code> and the global assumption mode. The <code>static</code> restriction replaces the use of <code>axiom</code> for static analysis (and suppresses odr-use), removing the overloading with its use for assumptions for optimization. The role played by <code>audit</code> is much the same as in the current draft. The principal purpose of <code>always</code> is to allow the contract syntax to be used with no global control at all (in which case the only reasonable behavior is checking).</p>
<p>The meaningful combinations of the modifiers and the sets of behaviors they supply are</p>
<ol style="list-style-type: decimal">
<li>(none): {<em>ignore</em>, <em>assume</em>, <em>enforce</em>}</li>
<li><code>tentative</code>: {<em>ignore</em>, <em>enforce</em>}</li>
<li><code>continue</code>: {<em>ignore</em>, <em>assume</em>, <em>inform</em>}</li>
<li><code>tentative continue</code>: {<em>ignore</em>, <em>inform</em>}</li>
<li><code>static</code>: {<em>ignore</em>, <em>assume</em>}</li>
<li><code>static tentative</code>: {<em>ignore</em>}</li>
<li><code>audit</code>: {<em>ignore</em>, <em>assume</em>, <em>enforce</em>?}</li>
<li><code>audit tentative</code>: {<em>ignore</em>, <em>enforce</em>?}</li>
<li><code>audit continue</code>: {<em>ignore</em>, <em>assume</em>, <em>inform</em>?}</li>
<li><code>audit tentative continue</code>: {<em>ignore</em>, <em>inform</em>?}</li>
<li><code>always</code>: {<em>enforce</em>}</li>
<li><code>always continue</code>: {<em>inform</em>}</li>
</ol>
<p>Because the build level makes <code>audit</code> equivalent either to <code>static</code> or to nothing, there are 8 unique sets available. It would be reasonable to make certain combinations like <code>always static</code> ill-formed, but note that <code>static audit</code> is just equivalent to <code>static</code> and merits at most a warning.</p>
<h2 id="use-cases">Use cases</h2>
<p>The safety goals of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1290r3.pdf">P1290R3</a> can be achieved with the global assumption mode.</p>
<p>P1332R0 proposes several features to satisfy its extensive set of use cases. Several of these (that also appear in P1429R2) are covered by this simpler proposal:</p>
<ol style="list-style-type: decimal">
<li>The <code>ignore</code> semantic as a choice for a contract level is provided via the global assumption mode.</li>
<li>The use of the <code>%review</code> tag to suppress uncontrolled optimizations and prevent crashes from new contracts is addressed by the <code>tentative</code> restriction and <code>continue</code> modifier respectively.</li>
<li>The manual choices of semantics (which of course provide access to certain singleton sets of behaviors) are supported:
<ol style="list-style-type: decimal">
<li><code>ignore</code>: <code>tentative static</code> (though less likely to be ignored by a static analyzer), or just <code>static</code> with the global assumption mode <em>off</em></li>
<li><code>assume</code>: <code>static</code></li>
<li><code>check_maybe_continue</code>: <code>always continue</code> (but see below about optimization)</li>
<li><code>check_never_continue</code>: <code>always</code></li>
</ol></li>
<li>The mixed treatment of <code>audit</code> and <code>default</code> contracts is supported by adding <code>continue</code> to checks past which it is known to be safe to continue.</li>
</ol>
<p>Most of the others may be addressed elsewhere:</p>
<ol style="list-style-type: decimal">
<li>The modes per-library may be much easier to realize as per-module (since per-translation-unit doesn’t mix well with <code>#include</code>).</li>
<li>The <code>check_maybe_continue</code> optimization barrier is realized more generally by <code>std::observable</code> from P1494R0.</li>
</ol>
<p><code>check_always_continue</code> is not addressed, but it appears to be outside the scope of the language to restrict optimization in such a fashion.</p>
<h1 id="acknowledgments">Acknowledgments</h1>
<p>Thanks to John Lakos for a detailed review of the first published version. Thanks to Joshua Berne for writing P1807R0, which discussed this paper and inspired improvements.</p>
</body>
</html>
