Операторы Shift, упорядоченные в С++ 17

Я читал в С++ 17 Standard $ 8.5.7.4:

Выражение E1 секвенируется перед выражением E2.

для операторов сдвига.

Также правило 19 правила cppreference говорит:

In a shift operator expression E1<<E2 and E1>>E2, every value
computation and side-effect of E1 is sequenced before every value
computation and side effect of E2

Но когда я пытаюсь скомпилировать следующий код с gcc 7.3.0 или clang 6.0.0

#include <iostream>
using namespace std;

int main() {
    int i = 5;
    cout << (i++ << i) << endl;
    return 0;
}

Я получаю следующее предупреждение gcc:

../src/Cpp_shift.cpp: In function ‘int main():
../src/Cpp_shift.cpp:6:12: warning: operation on ‘i may be undefined [-Wsequence-point]
  cout << (i++ << i) << endl;
           ~^~

Предупреждение о кланге:

warning: unsequenced modification and access to 'i' [-Wunsequenced]

Я использовал следующие команды для компиляции:

g++ -std=c++17 ../src/Cpp_shift.cpp -o Cpp_shift -Wall
clang++ -std=c++17 ../src/Cpp_shift.cpp -o Cpp_shift -Wall

Я получаю ожидаемый результат 320 в обоих случаях (5 * 2 ^ 6)

Может кто-нибудь объяснить, почему я получаю это предупреждение? Я что-то пропустил? Я также прочитал этот связанный вопрос, но он не отвечает на мой вопрос.

edit: все остальные варианты ++i << i, i << ++i и i << i++ приводят к i << i++ же предупреждению.

edit2: (i << ++i) приводит к 320 для clang (правильно) и 384 для gcc (неверно). Кажется, что gcc дает неправильный результат, если ++ находится в E2, (i << i++) также дает неправильный результат.

Ответы

Ответ 1

Стандарт ясно описывает порядок оценки операндов оператора сдвига.

n4659 - §8.8 (p4):

Выражение E1 секвенируется перед выражением E2.

В выражении i++ << i нет неопределенного поведения, оно четко определено. Это ошибка в Clang и GCC.