<html>
<head>
<title>N3218: Core Issue 1125: Unclear definition of "potential constant
expression" (DE 8, GB 26)</title>

<style type="text/css">
  ins { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
  del { text-decoration:line-through; background-color:#FFA0A0 }
</style>
</head>

<body>
Jens Maurer<br/>
2010-11-12<br/>
N3218=10-0208

<h1>N3218: Core Issue 1125: Unclear definition of "potential constant
expression" (DE 8, GB 26)</h1>

This paper presents the detailed changes to the C++ Working Draft
N3126 to address core issue 1125, i.e. FCD comment DE 8.  The
definition of "function invocation substitution" in the changes below
also resolves core issue 1127, i.e. FCD comment GB 26.
<p>

Change in 3.6.2 basic.start.init paragraph 2 as indicated:

<blockquote>
<em>Constant initialization</em> is performed:
<ul>
<li>...</li>
<li>if an object with static or thread storage duration is initialized
<del>such that the initialization satisfies the requirements for the object
being declared with constexpr (7.1.5 dcl.constexpr).</del>
<ins>by a constructor call, if the constructor is a constexpr
constructor, if all constructor arguments are constant expressions
(including conversions), and if, after function invocation
substitution (7.1.5 dcl.constexpr), every constructor call and
full-expression in the <em>mem-initializer</em>s is a constant
expression</ins> </li>
<li><ins>if an object with static or thread storage duration is
not initialized by a constructor call and if every full-expression that
appears in its initializer is a constant expression.</ins></li>
</ul>
</blockquote>


Change in 5.19 expr.const paragraph 2:

<blockquote>
<ul>
<li>an invocation of a function other than <ins>a constexpr
constructor for a literal class or</ins> a constexpr function <del>or
a constexpr constructor</del> [ Note: overload
resolution (13.3) is applied as usual -- end note ];</li>
<li>...</li>
<li>an invocation of a <code>constexpr</code> function
with arguments that, when
<ins>substituted by function invocation substitution (7.1.5 dcl.constexpr)</ins>
<del>implicitly converted to the
corresponding parameter types
and substituted for the corresponding parameters in the potential
constant expression of the <code>constexpr</code> function, and
the resulting expression implicitly converted to the return
type</del>, do not produce a constant expression;
</del> [
Example:
<pre>
constexpr const int* addr(const int& ir) { return &ir; } // OK
static const int x = 5;
constexpr const int* xp = addr(x); // OK: (const int*)&(const int&)x is an
                                    // address contant expression
constexpr const int* tp = addr(5); // error, initializer for constexpr variable not a constant
         // expression; (const int*)&(const int&)5 is not a constant
         // expression because it takes the address of a temporary
</pre>
] </li>

<li><ins>an invocation of a <code>constexpr</code> constructor with
arguments that, when substituted by function invocation
substitution (7.1.5 dcl.constexpr), do not produce all constant
expressions for the constructor calls and full-expressions in the
<em>mem-initializer</em>s;

[ Example:
<pre>
  int x;                          // not constant
  struct A {
    constexpr A(bool b) : m(b ? 42 : x) { }
    int m;
  };
  constexpr int v = A(true).m;    // ok, constructor call initializes
                                  // m with the value 42 after substitution
  constexpr int w = A(false).m;   // error: initializer for m is
                                  // "x", which is non-constant
</pre>
]</ins></li>
<li>...</li>
<li> an <em>id-expression</em> that refers to a variable or data member of
reference type; [ Footnote: Use of a reference parameter of a
<code>constexpr</code> function does not prevent the <ins>function from
being used in constant expressions, because function invocation
substitution will replace the parameters with the argument
expressions.</ins> <del>body from being a
potential constant expression because the parameters are replaced by
constant expressions during that determination, and later by arguments
to a call. </del> ]</li>
<li>...</li>
</ul>
</blockquote>

Remove 5.19 expr.const paragraph 6 entirely:

<blockquote>
<del>
An expression is a <em>potential constant expression</em> if it is a
constant expression when all occurrences of function parameters are
replaced as follows:</del>
<ul>
<li><del>for non-reference parameters, by arbitrary prvalue constant
expressions of the appropriate types;</del></li>
<li><del>for lvalue reference parameters, by arbitrary variables of the
referred-to types with static storage duration initialized with
constant expressions; or</del></li>
<li><del>for rvalue reference parameters, by arbitrary prvalue constant
expressions of the referred-to types implicitly converted to the types of the parameters.</del></li>
</ul>
</blockquote>

Change in 7.1.5 dcl.constexpr paragraph 3 as indicated:

<blockquote>
<ul>
<li>its <em>function-body</em> shall be a
<em>compound-statement</em> of the form
<pre>
      { return <em>expression</em> ; }
</pre>
<del>where <em>expression</em> is a potential constant expression
(5.19 expr.const)</del>
</ul>
[ Example: ... ]
</blockquote>


Change 7.1.5 dcl.constexpr paragraph 4 as indicated:

<blockquote>
<ul>
<li><del>every constructor argument and full-expression in a
<em>mem-initializer</em> shall be a potential constant
expression</del></li>
</ul>
A trivial copy/move constructor is also a <del>constexpr</del> <ins><code>constexpr</code></ins> constructor.
[ Example: ... ]
</blockquote>


In 7.1.5 dcl.constexpr, add a new paragraph after the current paragraph 4:

<blockquote>
<ins>
<em>Function invocation substitution</em> for a call of a
<code>constexpr</code> function or of a <code>constexpr</code>
constructor means to convert implicitly each argument expression to
the corresponding parameter type as if by copy-initialization
[ Footnote: The resulting converted value will include an
lvalue-to-rvalue conversion (4.1 conv.lval) if the corresponding
copy-initialization requires one.  --end footnote], to
substitute that converted expression for each use of the corresponding
parameter in the function-body, and, for constexpr functions, to
convert implicitly the resulting expression to the return type of the
function.  Such substitution does not change the meaning.

[ Example:</ins>
<pre>
<ins>constexpr int f(void *) { return 0; }
constexpr int f(...) { return 1; }
constexpr int g1() { return f(0); }         // calls f(void *)
constexpr int g2(int n) { return f(n); }    // calls f(...) even for n == 0
constexpr int g3(int n) { return f(n*0); }  // calls f(...)

namespace N {
  constexpr int c = 5;
  constexpr int h() { return c; }
}
constexpr int c = 0;
constexpr int g4() { return N::h(); }  // value is 5, "c" is not looked up again after the substitution</ins>
</pre>
<ins>]

For a constexpr function, if no function argument values exist such
that the function invocation substitution would produce a constant
expression (5.19 expr.const), the program is ill-formed; no diagnostic
required.

For a constexpr constructor, if no argument values exist such that
after function invocation substitution, every
constructor call and full-expression in the
<em>mem-initializer</em>s
would be a constant expression (including conversions),
the program is ill-formed; no diagnostic required. [ Example:</ins>
<pre>
<ins>constexpr int f(bool b) { return b ? throw 0 : 0; }   // ok
constexpr int f() { throw 0; }         // ill-formed, no diagnostic required

struct B {
  constexpr B(int x) : i(0) { }    // "x" is unused
  int i;
};

int global;

struct D : B {
  constexpr D() : B(global) { }   // ill-formed, no diagnostic required
                                  // lvalue-to-rvalue conversion on non-constant "global"
};</ins>
</pre><ins>
]</ins>
</blockquote>


Change 7.1.5 dcl.constexpr paragraph 8 as indicated:

<blockquote>
A <code>constexpr</code> specifier used in an object declaration
declares the object as <code>const</code>. Such an object
<ins>shall have literal type and</ins> shall be initialized.

If it is initialized by a constructor call, <del>the
constructor shall be a
<code>constexpr</code> constructor and every argument to the
constructor shall be a constant expression</del> <ins>that call shall
be a constant expression (5.19 expr.const)</ins>.


Otherwise, every full-expression that
appears in its initializer shall be a constant expression.

Each implicit conversion used in converting the
initializer expressions and each constructor call used for the
initialization shall be one of those allowed in a constant expression
(5.19 expr.const). [ Example: 
<pre>
struct pixel {
  int x, y;
};
constexpr pixel ur = { 1294, 1024 };// OK
constexpr pixel origin;             // error: initializer missing
</pre>
 ]
</blockquote>

</body>
</html>
