24

Clang accepts the following code, but gcc rejects it.

void h() { }

constexpr int f() {
    return 1;
    h();
}

int main() {
    constexpr int i = f();
}

Here is the error message:

g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'constexpr int f()':
main.cpp:5:6: error: call to non-'constexpr' function 'void h()'
     h();
     ~^~
main.cpp: In function 'int main()':
main.cpp:9:24: error: 'constexpr int f()' called in a constant expression
     constexpr int i = f();
                       ~^~
main.cpp:9:19: warning: unused variable 'i' [-Wunused-variable]
     constexpr int i = f();

This could well be the case where both compilers are correct, once we consider [dcl.constexpr]/5, given that f() is not a constant expression, as it doesn't satisfy [expr.const]/(4.2), as it calls a non-constexpr function h. That is, the code is ill-formed, but no diagnostic is required.

One other possibility is that the code is well formed, as [expr.const]/(4.2) doesn't apply in this case because the call to h in f is not evaluated. If this is the case, gcc is wrong and clang is correct.

  • 6
    Clang does not allow calling h() before returning, so the real question here is: Is a compiler allowed to ignore dead ill-formed code? – idmean Apr 18 at 19:12
  • "as it calls a non-constexpr function h". But it doesn't actually call h. I'd say that gcc is wrong here. – geza Apr 18 at 19:15
  • I'm adding the C++14 tag since on C++11 there's no question that it's ill-formed. – Barry Apr 18 at 19:29
  • 1
    This code works in GCC's trunk.. godbolt.org/z/f04MCq and godbolt.org/z/bAyE8a .. So it's already fixed.. Free upvotes. If compiled with GCC 8.3 it will fail but compile with Trunk and it works fine. – Brandon Apr 18 at 19:31
24

Clang is correct. A call to f() is a constant expression since the call to h() is never evaluated, so [dcl.constexpr]/5 doesn't apply. The call to h() in the body of f() is not ill-formed because the constraints on constexpr functions don't say anything about not being allowed to call non-constexpr functions. Indeed, a function like the following is well-formed because a call to it can be a constant expression when x is odd:

constexpr int g(int x) {
    if (x%2 == 0) h();
    return 0;
}
  • You answer seems to be correct, but I don't agree with your reasoning. Consider this: constexpr int f() { h(); return 1; }. In this case the code is ill-formed NDR according to [dcl.constexpr]/5 because the function f invokes a non-constexpr function h, and this is not allowed according to [expr.const]/(4.2). See also this question in SO. – Alexander Apr 18 at 20:34
  • 1
    @Alexander In the case where the call to h() is before the return statement, every call to f will fail to be a constant expression, and [dcl.constexpr]/5 applies. In the case where the call to h() is after the return statement, every call to f will be a constant expression, so [dcl.constexpr]/5 does not apply. – Brian Apr 18 at 20:36
  • Ok, but why did you say "The call to h() in the body of f() is not ill-formed because the constraints on constexpr functions don't say anything about not being allowed to call non-constexpr functions."? This is what is confusing in your answer. – Alexander Apr 18 at 20:42
  • 5
    @Alexander I'm not sure what part of that was unclear. I linked a section of the standard that lists the constructs that are forbidden from appearing in a constexpr function's body. A call to a non-constexpr function is not one of the forbidden constructs. However, if the call to the non-constexpr function becomes inevitable (i.e., occurs along all paths) then [dcl.constexpr]/5 becomes violated. – Brian Apr 18 at 20:47
  • 1
    @Alexander According to the rules of the language, the return statement returns control to the caller, skipping all remaining statements in the function. What about this is unclear? – Brian Apr 25 at 7:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.