<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<title>Non-literal variables (and labels and gotos) in constexpr functions</title>

	<style>
	p {text-align:justify}
	li {text-align:justify}
	blockquote.note
	{
		background-color:#E0E0E0;
		padding-left: 15px;
		padding-right: 15px;
		padding-top: 1px;
		padding-bottom: 1px;
	}
	ins {color:#00A000}
	del {color:#A00000}
	</style>
</head>
<body>

<address align=right>
Document number: P2242R1
<br/>
Audience: EWG, CWG
<br/>
<br/>
<a href="mailto:ville.voutilainen@gmail.com">Ville Voutilainen</a><br/>
2021-02-14<br/>
</address>
<hr/>
<h1 align=center>Non-literal variables (and labels and gotos) in constexpr functions</h1>

<h2>Credits</h2>

<p>
  Thanks to Richard Smith for reporting the problem and providing
  a thorough analysis of the implementation divergence, and for
  providing helpful suggestions for the wording. Any remaining
  bugs in this paper are the author's alone, not Mr. Smith's.
</p>

<h2>Abstract</h2>

<p>
  This paper proposes to strike the restriction that a constexpr
  function cannot contain a definition of a variable of non-literal
  type (or of static or thread storage duration), or a goto statement,
  or an identifier label. The rationale is briefly that the mere presence
  of the aforementioned things in a function is not in and of itself
  problematic; we can allow them to be present, as long as constant
  evaluation doesn't evaluate them.
</p>

<h3>To Emphasize: This proposal is explicitly and deliberately
  and intentionally NOT proposing that static or thread_local variables
  could be used in constant evaluation.</h3>

<p>
  With regards to consistency with other language constructs, namely
  that they're not ill-formed in function definitions but are ill-formed
  if an attempt is made to constant-evaluate them, this proposal
  is in P0592 priority bucket 2, since it's an Improvement, a consistency
  bug fix.
</p>
<p>
  However, this proposal is adding a capability that wasn't there before,
  so from that perspective, this is in P0592 priority bucket 3, an Addition.
</p>
<p>
  The suggestion of the proposal author is to treat this as an Improvement
  rather than an Addition. We are making the language more regular here.
</p>

<h2>Change history</h2>

<ul>
  <li>R1: This version; added a clarification that this is not proposing
    the abiility to constexpr-evaluate anything new, and added wording
    to make it so.</li>
  <li>R0: Initial version.</li>
</ul>

<h2>Background</h2>

<p>
  The problem was reported by Richard Smith on the reflectors. Mr. Smith
  provided the following testcase:
<blockquote>
  <pre>template&lt;typename T&gt; constexpr bool f() {
  if (std::is_constant_evaluated()) {
    // ...
    return true;
  } else {
    T t;
    // ...
    return true;
  }
}
struct nonliteral { nonliteral(); };
static_assert(f&lt;nonliteral&gt;());</pre>
</blockquote>
</p>
<p>
  As Mr. Smith also suggested, this is
  <ol>
    <li>rejecting reasonable code</li>
    <li>inconsistent with the general direction of allowing various
      constructs in non-constant regions of constexpr functions.</li>
  </ol>
</p>

<p>
  According to tests on multiple compilers, there's implementation
  divergence; some accept the testcase, some reject it, and for some
  it depends on exactly how the testcase function body is written. While
  some of that may be due to imperfections in implementations,
  the standard is inconsistent here; the wording is probably clear
  as such, but the declaration special cases that remain in the specification
  seem undesirable.
</p>

<p>
  We have allowed a constexpr function to contain a throw-expression
  since C++11, as long as constant evaluation doesn't evaluate it.
  We have since extended the set of allowed things to contain, for
  example, inline assembly. Removing the restriction of variable
  definitions seems perfectly in line with the general direction
  we've been going towards.
</p>
<p>
  There's another even bigger and longer-term trend that this proposal follows.
  With this change, we move further into the direction of not diagnosing
  language constructs at declaration/definition time, but at the time of
  use. And if they're actually not used, there are no diagnostics.
</p>

<h2>A considered smaller change</h2>

<p>
  Now, we could entertain providing just a small fix for this problem,
  and indeed just lift the requirement for variable definitions. But
  there are two restrictions right next to it in the standard, forbidding
  the presence of gotos and labels in a constexpr functions. These
  language constructs, however, are fine as long as they're not
  constant-evaluated. Thus the proposal here is to strike those
  restrictions while we're at it.
</p>

<h2>Proposed wording</h2>

<p>
  In [dcl.constexpr]/3, strike the last bullet:
  <blockquote>
    <del>its function-body shall not enclose
    <ul><li>a goto statement,</li>
    <li>an identifier label,</li>
    <li>a definition of a variable of non-literal type or of static or thread storage duration.</li></ul>
    <p>[Note 3: A function-body that is = delete or = default encloses none of the above.
— end note]</p></del>
  </blockquote>
</p>
<p>
  In [expr.const]/5, add new bullets in the beginning and at the end:
  <blockquote>
    <ul>
      <li>this (7.5.2), except in a constexpr function (9.2.6) that is being evaluated as part of E;</li>
      <ins><li>an initialization of a static or thread_local variable;</li></ins>
      <li>...</li>
      <li>an asm-declaration (9.10);<del> or</del></li>
      <li>an invocation of the va_arg macro ([cstdarg.syn])<del>.</del><ins>; or</ins></li>
      <ins><li>a goto statement ([stmt.goto]).</li></ins>
    </ul>
  </blockquote>
</p>
</body>
</html>
