<html>
<head>
<title>N3260: Consolidated corrections for a cluster of constexpr concerns</title>

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

<body>
Jens Maurer<br/>
N3260=11-0030<br/>
2011-03-22

<h1>N3260: Consolidated corrections for a cluster of constexpr concerns</h1>

This paper presents the wording changes relative to the Working Paper
N3242 to address the following core issues:
<ul>
<li>Core Issue 1197: Constexpr arrays</li>
<li>Core Issue 1060: Scoped enumerators in integral constant
expressions (see also FCD comments US 2 and CH 1)</li>
<li>Core Issue 1100: constexpr conversion functions and non-type template arguments</li>
</ul>

Due to the volume of the changes, they were not integrated into the core issues list. 

<p>

Change in 5.19 expr.const paragraph 2 as indicated:

<blockquote>
A <em>conditional-expression</em> is a <del>constant expression</del>
<ins><em>core constant expression</em></ins> unless it involves one of
the following ...
<ul>
<li>...</li>
<li><del>an array-to-pointer conversion (4.2 conv.array) that
is applied to a glvalue that does not designate an object
with static storage duration;</del></li>
<li><del>a unary operator & (5.3.1 expr.unary.op) that is applied to
an lvalue that does not designate an object with static
storage duration;</del></li>
<li>an <em>id-expression</em> that refers to a variable or data
member of reference type [ Footnote: ... ];</li>
<li>...</li>
</ul>
</blockquote>

Change in 5.19 expr.const paragraph 3 as indicated:
<blockquote>
<del>A constant expression is an <em>integral constant expression</em>
if it is of integral or enumeration type.</del>
<ins>A <em>literal constant expression</em> is a prvalue core
constant expression of literal type, but not pointer type.
An <em>integral constant expression</em> is a literal
constant expression of integral or unscoped
enumeration type.</ins> [ Note: such expressions may be used as array
bounds (8.3.4 dcl.array, 5.3.4 expr.new), <del>as case expressions (6.4.2
stmt.switch),</del> as bit-field lengths (9.6 class.bit), as enumerator
initializers <ins>if the underlying type is not
fixed</ins> (7.2 dcl.enum), <ins>as
null pointer constants (4.10 conv.ptr), and as alignments (7.6.2
dcl.align)</ins> <del>and as integral or enumeration non-type template
arguments (14.3 temp.arg)</del>. -- end note ]
<ins>A <em>converted constant expression</em> of type T is
a literal constant expression, implicitly converted to type
T, where the implicit conversion (if any) is permitted in a
literal constant expression and the
implicit conversion sequence contains only user-defined conversions,
lvalue-to-rvalue conversions (4.1 conv.lval), integral promotions (4.5
conv.prom), and integral conversions (4.7 conv.integral) other than
narrowing conversions (8.5.4 dcl.init.list). [ Note: such expressions
may be used as case expressions (6.4.2 stmt.switch), as enumerator
initializers if the underlying type is fixed (7.2 dcl.enum), and as
integral or enumeration non-type template arguments (14.3
temp.arg). ]  A <em>reference
constant expression</em> is an lvalue core
constant expression that designates an object with static storage
duration or a function.  An <em>address constant expression</em> is a
prvalue core constant expression of pointer type that evaluates to the 
address of an object with static storage duration, to the address of
a function, or to a null pointer value, 
or a prvalue core constant expression of type
<code>std::nullptr_t</code>.
Collectively, literal constant expressions, reference
constant expressions, and address constant expressions are called
<em>constant expression</em>s.</ins>
</blockquote>


Change in 5.19 expr.const paragraph 5 as indicated:
<blockquote>
If an expression of literal class type is used in a context where an
integral constant expression is required,
then that class type shall have a single non-explicit conversion
function to an integral or <ins>unscoped</ins> enumeration type
and that conversion function shall be <del>constexpr</del>
<ins><code>constexpr</code></ins>. [ Example: ... ]
</blockquote>

Change in 6.4.2 stmt.switch paragraph 2 as indicated:
<blockquote>
Any statement
within the switch statement can be labeled with one or more case
labels as follows:
<pre>
      case <em>constant-expression</em> :
</pre>
where the <em>constant-expression</em> shall be
<del>an integral</del> <ins>a converted</ins> constant expression</ins>
(5.19 expr.const)<del>. The
integral constant expression is implicitly converted to</del>
<ins>of</ins> the promoted type of the switch condition.
</blockquote>

<em>Editing note: This allows scoped enumerators as case labels given
that they're no longer part of "integral constant expression"; see
above.   Since we know the exact target type, we can use that
information to disambiguate several conversions from a literal class
type.</em>

<p>

Change in 7.2 dcl.enum paragraph 2 as indicated:
<blockquote>
... An <em>enumerator-definition</em> with = gives the associated
<em>enumerator</em> the value indicated by the
<em>constant-expression</em>.  <del>The
<em>constant-expression</em> shall be an integral constant expression
(5.19 expr.const).</del> If the first <em>enumerator</em> has no
<em>initializer</em>, the value of the corresponding constant is
zero. ...
</blockquote>

Change in 7.2 dcl.enum paragraph 5 as indicated:
<blockquote>
... If the underlying type is fixed, the type of each
<em>enumerator</em> prior to the closing brace is the underlying
type<ins> and the <em>constant-expression</em> in the
<em>enumerator-definition</em> shall be a converted constant
expression of the underlying type (5.19 expr.const)</ins>;
if the initializing value of an <em>enumerator</em> cannot be
represented by the underlying type, the program is ill-formed.  If the
underlying type is not fixed, the type of each enumerator is the type
of its initializing value:
<ul>
<li>If an initializer is specified for an enumerator, the initializing
value has the same type as the expression<ins> and the
<em>constant-expression</em> shall be an integral constant expression
(5.19 expr.const)</ins>.</li>
<li>...</li>
</ul>
</blockquote>

Change in 14.3.2 temp.arg.nontype paragraph 1 as indicated:
<blockquote>
A <em>template-argument</em> for a non-type, non-template
<em>template-parameter</em> shall be one of:
<ul>
<li><ins>for a non-type <em>template-parameter</em> of integral or
enumeration type,</ins> <del>an integral</del> <ins>a converted</ins>
constant expression
(<del>including a constant expression of literal class type that can be
used as an integral constant expression as described in </del>5.19
expr.const) <ins>of the type of the <em>template-parameter</em></ins>;
or</li>
<li>...</li>
</blockquote>

Change in 14.3.2 temp.arg.nontype paragraph 5 as indicated:
<blockquote>
The following conversions are performed on each expression used as a
non-type <em>template-argument</em>. If a non-type
<em>template-argument</em> cannot be converted to the type of the
corresponding <em>template-parameter</em> then the program is
ill-formed.
<ul>
<li><del>for</del> <ins>For</ins> a non-type
<em>template-parameter</em> of integral or enumeration type,
<del>integral promotions (4.5) and integral conversions (4.7)</del>
<ins>conversions permitted in a converted constant expression (5.19
expr.const)</ins> are applied.
 </li>
<li>...</li>
</ul>
</blockquote>

<em>Editing note: 
The changes to 5.19 prohibit that a scoped
enumerator could be used as an array bound, without a cast.  Also,
previously, a scoped enumerator could be used to initialize an
enumerator of another scoped enumeration type (because it used to be
covered by "integral constant expression"), which is surprising.
Switch statements and template arguments are special in that the
specific target type is actually known, and scoped enumerations are no
problem.</em>

</body>
</html>
