4

From what I gather from this answer, a constexpr function's result is not a constant-expression if the function has not been declared yet. What surprises me is the following code snippet :

constexpr int f();

constexpr int g() {
    return f();
}

constexpr int f() {
    return 42;
}

int main() {
    constexpr int i = g();
    return i;
}

This compiles without trouble and works. Moving f's definition past main triggers error: 'constexpr int f()' used before its definition, as I would expect.

I presume that it works because f has been defined before the call to g, thus both calls are constant expressions.

Why are f() and g() apparently constant-expressions, even though f isn't defined when it is called by g? How is this described by the Standard?

I have tested this on Coliru's GCC 6.1.0 and Clang 3.8.0.

Community
  • 1
  • 1
Quentin
  • 62,093
  • 7
  • 131
  • 191
  • 1
    5.20/(2.3): "unless ... invocation of an undefined `constexpr` function"? – Kerrek SB May 30 '16 at 13:05
  • I think what we should accentuate is the fact that the `constexpr` function needs to have a definition only once it's `odr-used`. So even though `f()` doesn't have a definition in `g()`, the compiler can guess the body of `g()` with a simple declaration, but to actually call `g()`, you need the definition of `f()`, because calling a function is considered an `odr-use`. So yes, the given answer is valid, but I think this is what OP was confused about – KABoissonneault May 30 '16 at 13:25
  • 3
    See [CWG2166](http://wg21.link/CWG2166). – T.C. May 30 '16 at 15:46
  • @T.C. That looks like an answer to me :) – Quentin Jun 01 '16 at 09:45

2 Answers2

0

It is not necessary to define a constexpr before it is used. However, the result of calling it before its definition is not constexpr. Consequently, the compiler rightfully complains because you're trying to initialize a constexpr variable with a non-constant expression.

§5.20/p2 Constant expressions [expr.const] (Emphasis Mine) :

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:

...

(2.3) — an invocation of an undefined constexpr function or an undefined constexpr constructor;

101010
  • 41,839
  • 11
  • 94
  • 168
  • Sorry, I think my question wasn't clear. What I'm asking is why the call *is* actually a constant-expression, even though `f` is not defined at the point it is called ? – Quentin May 30 '16 at 13:15
  • Your quote can be read both as allowing and as disallowing the OP's code, it's not clear how you're reading it, and it's not clear whether that reading (whichever it is) is the right one. –  May 30 '16 at 13:15
  • 1
    Given your edit: this leaves an important question still unanswered. Does [dcl.constexpr]p5 ("For a non-template, non-defaulted constexpr function [...], if no argument values exist such that an invocation of the function [...] could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no diagnostic required.") allow a compiler to immediately issue an error message after the definition of `g`? Prior to the definition of `f`, there are no argument values to make the result of the evaluation of `g()` a constant expression. –  May 30 '16 at 13:31
  • @hvd Hmmm... I believe this is debatable since "no diagnostic required". – 101010 May 30 '16 at 13:37
  • I think @hvd is onto what I'm trying to express -- when compiling `g`, `f()` cannot be a constant-expression, so how comes the "decision" is delayed until an actual call to `g()` ? – Quentin May 30 '16 at 13:44
  • @Quentin At that point the program is ill formed but no diagnostic is required. That is the compiler is not obliged to emit a diagnostic/error. Thus, you get the error later on when you're trying to initialize a `constexpr` with a non constant expression. – 101010 May 30 '16 at 15:01
0

As linked by T.C. in his comment, this is subject to a defect report.

According to 5.20 [expr.const] bullet 2.3, an expression is a constant expression unless (among other reasons) it would evaluate

  • an invocation of an undefined constexpr function or an undefined constexpr constructor;

This does not address the question of the point at which a constexpr function must be defined. The intent, in order to allow mutually-recursive constexpr functions, was that the function must be defined prior to the outermost evaluation that eventually results in the invocation, but this is not clearly stated.

This makes it clear that the example is well-formed and should indeed work as expected as long as f is defined before the call to g.

Community
  • 1
  • 1
Quentin
  • 62,093
  • 7
  • 131
  • 191