https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104803

            Bug ID: 104803
           Summary: if consteval error from branch that isn't evaluated
                    anyway
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example. Yes, the body of none_of here looks... extremely
bizarre. Just bear with me.

template <typename R, typename P>
constexpr auto none_of(R&& r, P p) -> bool {
    for (int i : r) {
        if consteval {
            if (p(i)) { // <== line 5
                return false;
            }
        } else {
            if (p(i)) { // <== line 9
                return false;
            }
        }
    }
    return true;
}

constexpr int vals[] = {1, 0, -1};
static_assert(none_of(vals,
    [](int i) consteval {
        return i > 2;
    }));

This does not compile, with the error (https://godbolt.org/z/dEq3381ac):

<source>: In instantiation of 'constexpr bool none_of(R&&, P) [with R = const
int (&)[3]; P = <lambda(int)>]':
<source>:18:22:   required from here
<source>:9:19: error: the value of 'i' is not usable in a constant expression
    9 |             if (p(i)) {
      |                   ^
<source>:3:14: note: 'int i' is not const
    3 |     for (int i : r) {
      |              ^
Compiler returned: 1

The error is on line 9. That's the second part of the if consteval, the "else"
part. That's not even supposed to be evaluated here, since we're in a
static_assert. If I replace it with 'return false':

template <typename R, typename P>
constexpr auto none_of(R&& r, P p) -> bool {
    for (int i : r) {
        if consteval {
            if (p(i)) {
                return false;
            }
        } else {
            return false;
        }
    }
    return true;
}

constexpr int vals[] = {1, 0, -1};
static_assert(none_of(vals,
    [](int i) consteval {
        return i > 2;
    }));

This compiles (https://godbolt.org/z/od93dEMf8). If 'return false;' in the else
branch were executed, this would've failed. But it's (correctly) not.

Something about the if consteval machinery is incorrectly evaluating the wrong
branch and failing as a result.

Reply via email to