Bug 86678 - constexpr evaluation incorrectly diagnoses unevaluated call to non-constexpr function
Summary: constexpr evaluation incorrectly diagnoses unevaluated call to non-constexpr ...
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: unknown
: P3 normal
Target Milestone: 9.0
Assignee: Jason Merrill
Keywords: rejects-valid
: 67026 (view as bug list)
Depends on:
Blocks: constexpr
  Show dependency treegraph
Reported: 2018-07-26 05:48 UTC by Eric Fiselier
Modified: 2021-08-28 21:25 UTC (History)
2 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2018-08-14 00:00:00


Note You need to log in before you can comment on or make changes to this bug.
Description Eric Fiselier 2018-07-26 05:48:54 UTC

#include <cassert>

template <class T>
constexpr int foo() {
    if (sizeof(T))
        return 1;
    assert(false && "BOOM!");

constexpr int V = foo<int>();
Comment 1 Jonathan Wakely 2018-07-26 10:33:22 UTC

void fail();

template <class T>
constexpr int foo() {
    if (sizeof(T))
        return 1;
    if (1)

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()'
Comment 2 Eric Fiselier 2018-07-26 10:40:26 UTC
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;
      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
Comment 3 Eric Fiselier 2018-07-26 10:50:06 UTC
The `if (1)` isn't essential either.

void fail();

template <class T>
constexpr int foo() {
    if (sizeof(T))
        return 1;

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>();
Comment 4 Jonathan Wakely 2018-08-14 16:09:23 UTC
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().
Comment 5 Jason Merrill 2018-09-08 16:00:59 UTC
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
	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.

Comment 6 Jason Merrill 2018-09-08 16:26:01 UTC
Fixed for GCC 9.
Comment 7 Ville Voutilainen 2018-11-14 09:11:17 UTC
*** Bug 67026 has been marked as a duplicate of this bug. ***
Comment 8 Jonathan Wakely 2019-05-13 09:53:44 UTC Comment hidden (obsolete)