3

In the current C++ standard there is the following paragraph (expr.const#5) (emphasis mine):

An integral constant expression is an expression of integral or unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression. [ Note: Such expressions may be used as bit-field lengths, as enumerator initializers if the underlying type is not fixed ([dcl.enum]), and as alignments. — end note ]

I have two questions regarding this definition:

  1. Does the phrase "implicitly converted to a prvalue" mean that for an expression to be considered an "integral constant expression" it must appear in a context that forces it to be implicitly converted to a prvalue?

  2. What does "the converted expression" refer to? I know that this question is addressed in Clarification of converted constant expression definition. The answer given there is that "the converted expression" is t, after the following initialization: T t = expr;. However, I do not see how evaluating that expression (t) would match any of the rules given in [expr.const#4] (paragraph describing required conditions for an expression to be considered a core constant expression) which would make it unqualified to be a core constant expression.

Thank you.

Passer By
  • 16,942
  • 5
  • 38
  • 81
user42768
  • 1,791
  • 7
  • 18
  • Weird, I thought the converted expression refers to the prvalue expression that is the result of the lvalue-to-rvalue conversion. – Passer By Jun 05 '19 at 16:57
  • 1
    @PasserBy To me it is strange to refer to the result of the lvalue-to-rvalue conversion as an expression, as I consider an expression only what I write in the program. Anyway, in order to determine whether an expression is a *core constant expression* one has to consider what happens during its evaluation. If "the converted expression" refers to the prvalue expression that is the result of the lvalue-to-rvalue conversion, what exactly is covered by the evaluation of such an expression? [continued] – user42768 Jun 05 '19 at 17:11
  • If, for example, the original expression is `f()` where `f` is declared as `int& f();`, does the evaluation of "the converted expression" include the statements executed inside the function `f`? – user42768 Jun 05 '19 at 17:14
  • @user42768: It’s considered an expression because things like value categories and the rules for constant evaluation are defined in terms of expressions (and consider just how many implicit expressions are introduced by, say, an implicitly defined assignment operator). Yes, the contents of `f` are considered; the [restrictions on constexpr](http://eel.is/c++draft/dcl.constexpr#3) functions are not nearly strong enough by themselves. – Davis Herring Jun 05 '19 at 18:26
  • @PasserBy: The standard [disagrees](http://eel.is/c++draft/basic.lval#3.sentence-2) about values having value categories, although it’s awfully close to correct to say that certain expressions just have reference type. – Davis Herring Jun 06 '19 at 23:53

2 Answers2

1

The statement that an integral constant expression is implicitly converted to a prvalue means that the lvalue-to-rvalue conversion is applied to any expression used as an integral constant expression. In the one case where an expression might be an integral constant expression—initializing a non-local object of const-qualified integer type that might be usable in constant expressions—the initializer is a prvalue anyway, so no change of interpretation can occur.

Beyond that, both of your questions have the same answer: whatever conversions are necessary to bring the expression (as written) to a prvalue integral type must also be allowed in a core constant expression (see, for example, /4.7 just before your citation and /6 just after it). The “converted expression” comprises the conversion in the T t=e; interpretation, not just the id-expression t (which would, for instance, always be an lvalue).

Davis Herring
  • 24,173
  • 3
  • 25
  • 55
  • Thank you for your answer. My first question was whether the "implicitly converted to a prvalue" wording means that in order for an expression to be considered an "integral constant expression" it has to be used in a context that requires it to be converted to a prvalue, not necessarily about the conversion itself. [continued] – user42768 Jun 05 '19 at 19:02
  • For my second question, you are saying that the "converted expression" wording means the "conversion process". I understand that semantically it is related to that, however (syntactically) I expect the term "converted expression" to refer to an expression (whether it is the one "as written" or the one after the lvalue-to-rvalue conversion). – user42768 Jun 05 '19 at 19:03
  • @user42768: I added some explanation about the prvalue conversion circumstances. As for an expression, it is the expression written, given a certain contextual interpretation (as for an `if` condition, which might invoke `operator bool`). – Davis Herring Jun 05 '19 at 19:41
  • *"the initializer is a prvalue anyway"*, huh? `constexpr int i = 42; constexpr int j = i;` isn't a prvalue initializer, but the result of applying l-t-r is. – Passer By Jun 06 '19 at 05:08
  • @PasserBy: Of course I meant that it is converted to a prvalue (like `int i;` in `i+1`) regardless of whether it turns out to be a constant expression, such that it doesn’t matter whether the lvalue-to-rvalue conversion is allowable in a constant expression. – Davis Herring Jun 06 '19 at 05:48
  • 1
    @DavisHerring So you are saying that "the converted expression" means the original expression plus the context in which it is used, which means that the evaluation of "the converted expression" comprises both the evaluation of the original expression and also the evaluation of the required conversion. – user42768 Jun 06 '19 at 18:03
1

I looked at clang's source code, specifically, at the function "CheckConvertedConstantExpression" inside "SemaOverload.cpp". The operations performed there are as follows:

  1. find the required implicit conversion sequence
  2. check to see if only conversions listed in http://eel.is/c++draft/expr.const#7 are used
  3. perform the implicit conversion (at this step I believe a new expression is created, e.g. if the original expression is f() which is of class type A with a user-defined conversion function to int, and the context requires an int, then the new expression should be f().operator int())
  4. check if any narrowing conversions are required
  5. evaluate the expression generated at step 3 (which implicitly checks if it is a constant expression)

So I believe that, as stated in @Davis Herring's answer, the term "converted expression" means a new expression whose evaluation comprises both the evaluation of the original expression, as written in the program, and the evaluation of any required conversion.

user42768
  • 1,791
  • 7
  • 18