Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr bug in clang but not in gcc?

Let's take this simple example:

#include <iostream>

namespace foo {
    constexpr int main(int argc, char* argv[]) {
      // code
    }
}

int main(int argc, char* argv[])
{
    return foo::main(argc, argv);
}

Depend on what code is, clang will complain or no. If code is:

cout << "Hello!";
return 0;

clang complains:

error: constexpr function never produces a constant expression [-Winvalid-constexpr]

constexpr int main(int argc, char* argv[]) {

note: non-constexpr function 'operator<< >' cannot be used in a constant expression

    std::cout << "Hello!";

/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ostream:530:5: note: declared here

operator<<(basic_ostream<char, _Traits>& __out, const char* __s)

Fair enough, constexpr functions can't contain any cout statements, as we know. But what happens if we do this?

  for (int i = 0; i < argc; i++)
    std::cout << argv[i];

clang allows it! OK, but this can't possibly be a constexpr function even though it is marked constexpr, let's try to use it in constexpr context.

int arr[foo::main(argc, argv)];

It works! So it must be clang bug? Reason I say clang because gcc complains:

error: body of constexpr function 'constexpr int foo::main(int, char**)' not a return-statement

So my conclusion is clang is wrong and gcc is right.

like image 301
Tory Webster Avatar asked Feb 03 '14 23:02

Tory Webster


People also ask

Is constexpr always evaluated at compile time?

constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.

Is constexpr guaranteed?

A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.

Why constexpr instead of define?

#define directives create macro substitution, while constexpr variables are special type of variables. They literally have nothing in common beside the fact that before constexpr (or even const ) variables were available, macros were sometimes used when currently constexpr variable can be used.

Should I use const with constexpr?

const can only be used with non-static member functions whereas constexpr can be used with member and non-member functions, even with constructors but with condition that argument and return type must be of literal types.


2 Answers

Clang is correct here.

First example

Here, the code is:

constexpr int foo::main(int argc, char* argv[]) {
  std::cout << argv[i];
  return 0;
}

In C++11, this code is ill-formed, because the body contains an expression-statement, which is not permitted in a constexpr function definition.

In C++1y, this code is ill-formed with no diagnostic required, because a call to foo::main can never produce a constant expression (because it always calls operator<<(std::ostream&, const char*), which is not constexpr).

Second example

In this case, the code is:

constexpr int foo::main(int argc, char* argv[]) {
  for (int i = 0; i < argc; i++)
    std::cout << argv[i];
  return 0;
}

In C++11, this code is ill-formed, because it contains a for-statement.

In C++1y, this code is valid. In particular, foo::main(0, 0) is a constant expression (with value 0). Since foo::main is usable in a constant expression, Clang is not permitted to reject it, and does not do so.

Third example

int arr[foo::main(argc, argv)];

The array bound here is not a constant expression (because it reads argc and argv, which are not constant). However, Clang supports variable-length arrays as an extension by default. You can specify -pedantic-errors to put clang into strictly-conforming mode, and in that mode it will reject this code.

GCC's diagnostic:

error: body of constexpr function 'constexpr int foo::main(int, char**)' not a return-statement

is incorrect in both C++11 and C++1y. In C++11, it's incorrect because the rule is more subtle (the body of a constexpr function can contain typedefs and a few other constructs, not just return-statements). In C++1y, the rule no longer exists at all.

like image 134
Richard Smith Avatar answered Oct 12 '22 15:10

Richard Smith


You compile your code in C++1y mode which contains wording to relax constexpr restrictions including all looping statements.

Have a look at N3652 which introduced these changes.

like image 22
pmr Avatar answered Oct 12 '22 16:10

pmr