Jens Maurer
N3260=11-0030
2011-03-22

N3260: Consolidated corrections for a cluster of constexpr concerns

This paper presents the wording changes relative to the Working Paper N3242 to address the following core issues: Due to the volume of the changes, they were not integrated into the core issues list.

Change in 5.19 expr.const paragraph 2 as indicated:

A conditional-expression is a constant expression core constant expression unless it involves one of the following ...
Change in 5.19 expr.const paragraph 3 as indicated:
A constant expression is an integral constant expression if it is of integral or enumeration type. A literal constant expression is a prvalue core constant expression of literal type, but not pointer type. An integral constant expression is a literal constant expression of integral or unscoped enumeration type. [ Note: such expressions may be used as array bounds (8.3.4 dcl.array, 5.3.4 expr.new), as case expressions (6.4.2 stmt.switch), as bit-field lengths (9.6 class.bit), as enumerator initializers if the underlying type is not fixed (7.2 dcl.enum), as null pointer constants (4.10 conv.ptr), and as alignments (7.6.2 dcl.align) and as integral or enumeration non-type template arguments (14.3 temp.arg). -- end note ] A converted constant expression 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 reference constant expression is an lvalue core constant expression that designates an object with static storage duration or a function. An address constant expression 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 std::nullptr_t. Collectively, literal constant expressions, reference constant expressions, and address constant expressions are called constant expressions.
Change in 5.19 expr.const paragraph 5 as indicated:
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 unscoped enumeration type and that conversion function shall be constexpr constexpr. [ Example: ... ]
Change in 6.4.2 stmt.switch paragraph 2 as indicated:
Any statement within the switch statement can be labeled with one or more case labels as follows:
      case constant-expression :
where the constant-expression shall be an integral a converted constant expression (5.19 expr.const). The integral constant expression is implicitly converted to of the promoted type of the switch condition.
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.

Change in 7.2 dcl.enum paragraph 2 as indicated:

... An enumerator-definition with = gives the associated enumerator the value indicated by the constant-expression. The constant-expression shall be an integral constant expression (5.19 expr.const). If the first enumerator has no initializer, the value of the corresponding constant is zero. ...
Change in 7.2 dcl.enum paragraph 5 as indicated:
... If the underlying type is fixed, the type of each enumerator prior to the closing brace is the underlying type and the constant-expression in the enumerator-definition shall be a converted constant expression of the underlying type (5.19 expr.const); if the initializing value of an enumerator 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:
Change in 14.3.2 temp.arg.nontype paragraph 1 as indicated:
A template-argument for a non-type, non-template template-parameter shall be one of:
Change in 14.3.2 temp.arg.nontype paragraph 5 as indicated:
The following conversions are performed on each expression used as a non-type template-argument. If a non-type template-argument cannot be converted to the type of the corresponding template-parameter then the program is ill-formed.
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.