A-n-t-h-o-n-y
A-n-t-h-o-n-y

Reputation: 410

Undefined behavior warning on self-assignment comma operator operand in fold expression

I'm getting a warning from GCC 10.1 about possible undefined behavior. Clang 10 does not warn.

warning: operation on 'init' may be undefined [-Wsequence-point]

    |     (x = ... = (init = fold_op(init, elements), 0));
    |                   ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~

Here is the snippet causing the warning:

template <typename T, typename BinaryOp, typename... Pack>
constexpr auto reverse_reduce(T init, BinaryOp&& fold_op, Pack&&... elements) -> T
{
    auto x = 0;
    (x = ... = (init = fold_op(init, elements), 0));
    return init;
}

It's using an operator= and fold expression hack to perform a reverse 'iteration' over the parameter pack.

Is GCC right to warn here? or is it well defined behavior?

Here is as minimal as I can make it while still reproducing the error:

auto x = 0;
auto i = 0;
((x = (i = i, 0)) = (i = i, 0))

Everything I've read about sequence points, order of evaluation, and operator precedence/associativity leads me to think that this is well defined, but there are so many rules and I'm no expert.

One thing that makes me believe the warning is correct is that when I assign the result to a constexpr variable in clang, the result is different than in non-constexpr evaluation.

Upvotes: 1

Views: 163

Answers (1)

user3324131
user3324131

Reputation: 954

You can use lambda to get rid of the warning.

Example:

template <typename T, typename BinaryOp, typename... Pack>
constexpr auto reverse_reduce(T init, BinaryOp&& fold_op, Pack&&... elements) -> T {
    auto x = 0;
    auto inner = [&](const auto& v) {init = fold_op(init, v); };
    (x = ... = (inner(elements), 0));
    return init;
}

Upvotes: 1

Related Questions