Разрешено ли компилятору ослаблять то, что он считает неопределенным поведением в константном выражении?
Мы знаем, что операции, которые могут вызвать неопределенное поведение, не являются основными константными выражениями(параграф 2 раздела 5.19 проекта стандарта C++)
В тестах я сделал оба clang
а также gcc
Неопределенное поведение в constexpr как ошибка, но они несовместимы в случае левого и правого сдвига. Например, во всех этих случаях, которые рассматриваются как неопределенное поведение в соответствии с разделом 5.8
Сдвиг операторов с 1 по 3:
constexpr int x1 = 1 << 33 ; //Assuming 32-bit int
constexpr int x2 = 1 << -1 ;
constexpr int x3 = -1 << 1 ;
constexpr int x4 = 1 >> 33 ; //Assuming 32-bit int
constexpr int x5 = 1 >> -1 ;
clang
выдаст ошибку ( посмотрите вживую):
error: constexpr variable 'x1' must be initialized by a constant expression
constexpr int x1 = 1 << 33 ; //Assuming 32-bit int
^ ~~~~~~~
note: shift count 33 >= width of type 'int' (32 bits)
constexpr int x1 = 1 << 33 ; //Assuming 32-bit int
....
в то время как gcc
выдаст предупреждение, но все равно будет считать каждую переменную константным выражением ( см. вживую):
warning: left shift count >= width of type [enabled by default]
constexpr int x1 = 1 << 33 ; //Assuming 32-bit int
^
warning: left shift count is negative [enabled by default]
constexpr int x2 = 1 << -1 ;
...
Это выглядит как gcc
ошибка, но я знаю, что компилятор может дать более сильные гарантии поведения, стандарт говорит, что он не определен, и похоже, что gcc дает некоторые более сильные гарантии сдвигов. Это может в конечном итоге быть ошибкой, но это заставляет меня задуматься, допустил ли компилятор такую же свободу действий в контексте constexpr
также или компилятор должен строго придерживаться того, что стандарт говорит здесь неопределенное поведение?
Обновить
Как упоминает Алан, действительно верно, что диагностика плохо сформированной программы может быть либо ошибкой, либо предупреждением, но в этом случае gcc
похоже не считает программу плохо сформированной. В отличие от других случаев, таких как в случае переполнения, gcc
не жалуется на недействительных constexpr, но предупреждает о сменах. Так что тогда может показаться, что это либо ошибка, либо gcc
не считает эти случаи неопределенными и, следовательно, мой вопрос.
1 ответ
Поскольку Йоханнес, похоже, не хочет превращать свой комментарий в ответ, я отвечу сам. У меня был разговор в автономном режиме с Howard Hinnant, и он подтвердил согласие в комментариях, что gccs
поведение в этом контексте действительно соответствует.
Соответствующим разделом проекта стандарта будет раздел 1.4
Соответствие реализации, которое говорится в пункте 2:
Хотя этот международный стандарт устанавливает только требования к реализациям C++, эти требования часто легче понять, если они сформулированы как требования к программам, частям программ или выполнению программ. Такие требования имеют следующее значение:
и имеет следующую пулю (выделено мое):
Если программа содержит нарушение какого-либо диагностируемого правила или вхождение конструкции, описанной в настоящем стандарте как "условно поддерживаемую", когда реализация не поддерживает эту конструкцию, соответствующая реализация должна выдать как минимум одно диагностическое сообщение.
Диагностика может быть либо предупреждением, либо ошибкой. Так однажды gcc
выдает предупреждение о неопределенном поведении, которое не требует последующего предупреждения о самом constexpr.
Хотя это соответствует поведению, генерирующему ошибку для constexpr и позволяющему SFINAE казаться более устойчивым поведением. Учитывая, что gcc
выдает ошибки в других случаях неопределенного поведения в constexpr, это не похоже на предполагаемое поведение или, по крайней мере, на непоследовательное поведение, поэтому я подал отчет об ошибке.