Reproducer: #include <cassert> template <class T> constexpr int foo() { if (sizeof(T)) return 1; assert(false && "BOOM!"); } constexpr int V = foo<int>();
Reduced: void fail(); template <class T> constexpr int foo() { if (sizeof(T)) return 1; if (1) fail(); } constexpr int V = foo<int>(); a.cc:11:27: error: 'constexpr int foo() [with T = int]' called in a constant expression constexpr int V = foo<int>(); ~~~~~~~~^~ a.cc:4:15: note: 'constexpr int foo() [with T = int]' is not usable as a 'constexpr' function because: constexpr int foo() { ^~~ a.cc:8:11: error: call to non-'constexpr' function 'void fail()' fail(); ~~~~^~
This is a bug according to [expr.const]p2 which states: > An expression e is a core constant expression unless the evaluation of e, > following the rules of the abstract machine, would evaluate one of the > following expressions: > [...] The key phrase being "would evaluate one of". The example never evaluates a non-constant expression. GCC correctly accepts the control flow: template <class T> constexpr int foo() { if (sizeof(T)) return 1; else assert(false && "BOOM!"); } template <class T> constexpr int bar() { return sizeof(T) ? 1 : throw 42; } static_assert(foo() && bar()); In all both cases the unevaluated expressions do not cause constant evaluation to fail. [1] http://eel.is/c++draft/expr.const#2
The `if (1)` isn't essential either. void fail(); template <class T> constexpr int foo() { if (sizeof(T)) return 1; fail(); } constexpr int x = foo<int>(); It seems to have something to do with whether the initial `if` statement is fully covered, regardless of what's actually evaluated. (Note that the branches of the initial `if` are evaluated, or not evaluated, correctly). int fail(); template <class T> constexpr int foo() { if (sizeof(T)) return 1; else if (fail()) fail(); // OK // Fallthrough is also OK } constexpr int x = foo<int>();
constexpr bool always_true() { return true; } int f() { return 1; } constexpr int g() { if (always_true()) return 0; return f(); } ce.cc: In function 'constexpr int g()': ce.cc:6:11: error: call to non-'constexpr' function 'int f()' 6 | return f(); | ~^~ This makes it awkward to use the new __builtin_is_constant_evaluated().
Author: jason Date: Sat Sep 8 16:00:02 2018 New Revision: 264171 URL: https://gcc.gnu.org/viewcvs?rev=264171&root=gcc&view=rev Log: PR c++/86678 - constexpr function with non-constant after return. In this testcase, the call to f() can never be a constant expression, but that's not a problem because it isn't always reached by calls to g. We were wrongly rejecting this because potential_constant_expression_1 lacked the jump tracking that cxx_eval_constant_expression has. So this patch adds a simpler version of that tracking. * constexpr.c (potential_constant_expression_1): Add jump_target. (breaks): Check for BREAK_STMT. (continues): Check for CONTINUE_STMT. Added: trunk/gcc/testsuite/g++.dg/cpp1y/constexpr-return4.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/constexpr.c
Fixed for GCC 9.
*** Bug 67026 has been marked as a duplicate of this bug. ***
(In reply to Ville Voutilainen from comment #7) > *** Bug 67026 has been marked as a duplicate of this bug. *** Confirmed, it was fixed by r264171 for PR 67026.