The integer overflow built-ins like __builtin_mul_overflow are not usable in constant expressions even when their arguments themselves are constants such that the computations do not overflow. This prevents the builtins from being used by GCC itself to instrument VLAs defined in constexpr functions to detect overflow in the VLA bounds (see bug 69517 for background). For additional problem reports caused by not treating the overflow built-ins as constant expressions see bug 68120 and bug 68971. $ cat z.cpp && /home/msebor/build/gcc-69517/gcc/xg++ -B/home/msebor/build/gcc-69517/gcc -S -Wall -Wextra -Wpedantic -fdump-tree-optimized=/dev/stdout z.cpp constexpr int mul (int x, int y) { int z = 0; return __builtin_mul_overflow (x, y, &z) ? 0 : z; } constexpr int z1 = 1234 * 5678; // okay constexpr int z2 = mul (1234, 5678); // error z.cpp:8:24: in constexpr expansion of ‘mul(1234, 5678)’ z.cpp:4:35: error: call to internal function return __builtin_mul_overflow (x, y, &z) ? 0 : z; ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
For GCC's own instrumentation you should obviously not use these builtins, but the corresponding internal functions, otherwise you take address of something that doesn't need to be addressable. Whether we want to mark the builtins as constexpr is for us to decide, I bet as they are storing to what the last argument points to, it could be only usable in C++14 and later constexprs, right?
Thank you for the suggestion. Storing values via pointers is not C++ 14 specific so the answer to your question is that having the builtins be treated as constexpr would be useful in both C++ 11 and C++ 14 modes. The modified example below should help explain it: constexpr int mul (int x, int y, int z = 0) { return __builtin_mul_overflow *(x, y, &z) ? 0 : z; } constexpr int z = mul (1234, 5678);
Testing a patch.
Patch posted for review: https://gcc.gnu.org/ml/gcc-patches/2016-05/msg00013.html
Author: jakub Date: Wed Jun 8 19:03:17 2016 New Revision: 237238 URL: https://gcc.gnu.org/viewcvs?rev=237238&root=gcc&view=rev Log: PR c++/70507 PR c/68120 * builtins.def (BUILT_IN_ADD_OVERFLOW_P, BUILT_IN_SUB_OVERFLOW_P, BUILT_IN_MUL_OVERFLOW_P): New builtins. * builtins.c: Include gimple-fold.h. (fold_builtin_arith_overflow): Handle BUILT_IN_{ADD,SUB,MUL}_OVERFLOW_P. (fold_builtin_3): Likewise. * doc/extend.texi (Integer Overflow Builtins): Document __builtin_{add,sub,mul}_overflow_p. gcc/c/ * c-typeck.c (convert_arguments): Don't promote last argument of BUILT_IN_{ADD,SUB,MUL}_OVERFLOW_P. gcc/cp/ * constexpr.c: Include gimple-fold.h. (cxx_eval_internal_function): New function. (cxx_eval_call_expression): Call it. (potential_constant_expression_1): Handle integer arithmetic overflow built-ins. * tree.c (builtin_valid_in_constant_expr_p): Handle BUILT_IN_{ADD,SUB,MUL}_OVERFLOW_P. gcc/c-family/ * c-common.c (check_builtin_function_arguments): Handle BUILT_IN_{ADD,SUB,MUL}_OVERFLOW_P. gcc/testsuite/ * c-c++-common/builtin-arith-overflow-1.c: Add test cases. * c-c++-common/builtin-arith-overflow-2.c: New test. * g++.dg/ext/builtin-arith-overflow-1.C: New test. * g++.dg/cpp0x/constexpr-arith-overflow.C: New test. * g++.dg/cpp1y/constexpr-arith-overflow.C: New test. Added: trunk/gcc/testsuite/c-c++-common/builtin-arith-overflow-2.c trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-arith-overflow.C trunk/gcc/testsuite/g++.dg/cpp1y/constexpr-arith-overflow.C trunk/gcc/testsuite/g++.dg/ext/builtin-arith-overflow-1.C Modified: trunk/gcc/ChangeLog trunk/gcc/builtins.c trunk/gcc/builtins.def trunk/gcc/c-family/ChangeLog trunk/gcc/c-family/c-common.c trunk/gcc/c/ChangeLog trunk/gcc/c/c-typeck.c trunk/gcc/cp/ChangeLog trunk/gcc/cp/constexpr.c trunk/gcc/cp/tree.c trunk/gcc/doc/extend.texi trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c
r237238 lets GCC 7 accept the integer overflow built-ins in constant expressions whenever their arguments are.