Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Throw in constexpr function

The following piece of code compiles under clang++ 3.7.0 but is denied by g++ 5.3.1. Both have -std=c++14 option. Which compiler is correct? Anyone knows where in the standard talks about this? Thanks.

#include <stdexcept> using namespace std;  constexpr int f(int n) {   if (n <= 0) throw runtime_error("");   return 1; }  int main() {   char k[f(1)]; } 

Output

[hidden] g++ -std=c++14 c.cpp  c.cpp: In function ‘constexpr int f(int)’: c.cpp:7:1: error: expression ‘<throw-expression>’ is not a constant-expression  }  ^ [hidden] clang++ -std=c++14 c.cpp  [hidden]  [hidden] g++ -v Using built-in specs. COLLECT_GCC=/usr/bin/g++ COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/5.3.1/lto-wrapper Target: x86_64-redhat-linux Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --disable-libgcj --with-isl --enable-libmpx --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux Thread model: posix gcc version 5.3.1 20151207 (Red Hat 5.3.1-2) (GCC)  [hidden]  [hidden] clang++ -v clang version 3.7.0 (http://llvm.org/git/clang.git 2ddd3734f32e39e793550b282d44fd71736f8d21) Target: x86_64-unknown-linux-gnu Thread model: posix Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/3.4.6 Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/5.3.1 Selected GCC installation: /usr/lib/gcc/x86_64-redhat-linux/5.3.1 Candidate multilib: .;@m64 Candidate multilib: 32;@m32 Selected multilib: .;@m64 
like image 578
Kan Li Avatar asked Dec 15 '15 03:12

Kan Li


People also ask

Can you throw in a constexpr function?

Even though try blocks and inline assembly are allowed in constexpr functions, throwing exceptions or executing the assembly is still disallowed in a constant expression.

What is constexpr function in C++?

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.

Can constexpr functions call non constexpr functions?

A call to a constexpr function produces the same result as a call to an equivalent non- constexpr function , except that a call to a constexpr function can appear in a constant expression. The main function cannot be declared with the constexpr specifier.


Video Answer


1 Answers

clang is correct, note the HEAD revision of gcc accepts also accepts this code. This is a well-formed constexpr function, as long as there is value for the argument(s) that allows the function to be evaluated as a core constant expression. In your case 1 is such a value.

This is covered in the draft C++14 standard section 7.1.5 The constexpr specifier [dcl.constexpr] which tells us what is allowed in a constexpr function:

The definition of a constexpr function shall satisfy the following constraints:

  • it shall not be virtual (10.3);

  • its return type shall be a literal type;

  • each of its parameter types shall be a literal type;

  • its function-body shall be = delete, = default, or a compound-statement that does not contain

    • an asm-definition,

    • a goto statement,

    • a try-block, or

    • a definition of a variable of non-literal type or of static or thread storage duration or for which no initialization is performed.

no restriction on throw and it also says (emphasis mine):

For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no diagnostic required.

and below this paragraph we have the following example, similar to yours:

constexpr int f(bool b)   { return b ? throw 0 : 0; } // OK constexpr int f() { return f(true); } // ill-formed, no diagnostic required 

throw is not allowed in a core constant expression, which is covered in section 5.19 [expr.const] paragraph 2 which says:

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

and includes the following bullet:

  • a throw-expression (15.1).

and so f would not be usable in a core constant expression when n <= 0.

Update

As TemplateRex points out, there are two gcc bugs reports for this:

  • Never executed "throw" in constexpr function fails to compile
  • C++14] throw-expression is not a valid constant-expression

TemplateRex also notes the fixes are not applied to to 5.3.0 and are only in trunk. No, work arounds are provided.

like image 157
Shafik Yaghmour Avatar answered Oct 02 '22 03:10

Shafik Yaghmour