Std:: declval() ошибка утверждения обжига с предупреждениями в GCC

Рассмотрим этот фрагмент:

#include <utility>

template <typename U>
auto foo() -> decltype(std::declval<U>() + std::declval<U>());

template <typename T>
decltype(foo<T>()) bar(T)
{}

int main()
{
    bar(1);
    return 0;
}

Это вызывает предупреждение и статическую ошибку утверждения во всех версиях GCC. Я попробовал его (4.7.3, 4.8.1, 4.9-some- git) при компиляции с помощью -Wall -Wextra. Например, это результат 4.8.1:

main.cpp: In instantiation of ‘decltype (foo<T>()) bar(T) [with T = int; decltype (foo<T>()) = int]’:
main.cpp:12:7:   required from here
main.cpp:8:2: warning: no return statement in function returning non-void [-Wreturn-type]
 {}
  ^
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/move.h:57:0,
                 from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/stl_pair.h:59,
                 from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/utility:70,
                 from main.cpp:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/type_traits: In instantiation of ‘typename std::add_rvalue_reference< <template-parameter-1-1> >::type std::declval() [with _Tp = int; typename std::add_rvalue_reference< <template-parameter-1-1> >::type = int&&]’:
main.cpp:8:2:   required from ‘decltype (foo<T>()) bar(T) [with T = int; decltype (foo<T>()) = int]’
main.cpp:12:7:   required from here
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/type_traits:1871:7: error: static assertion failed: declval() must not be used!
       static_assert(__declval_protector::__stop,

Если либо отключить предупреждения, либо поставки bar с помощью оператора return, например,

template <typename T>
decltype(foo<T>()) bar(T a)
{
    return a + a;
}

ошибка утверждения исчезает. Clang++ 3.3 не вызывает ошибок утверждения в любом случае. Является ли это стандартно-совместимым поведением GCC?

+3
источник поделиться
2 ответа

Моя копия GCC 4.9, созданная в начале июня, компилирует ее без жалобы, пока я добавляю return {}; или throw; внутри функции. Без return он запускает это статическое утверждение. Это, конечно, ошибка, но только незначительная, поскольку функция только "сбой" при выполнении.

Я видел эту ошибку при попытке выполнить declval() в постоянном выражении, так что в вашем случае может произойти что-то подобное. "Нельзя использовать", по-видимому, ссылается на использование ODR или использование результата.

Возможно, в отсутствие какого-либо утверждения он попытался создать один с содержимым decltype. Добавление даже простого утверждения, такого как 0;, отключает ложную ошибку. (Но static_assert( true, "" ) или даже void(0) недостаточно.)

Подано сообщение ошибка GCC.

+4
источник

Я не считаю, что компилятор находится в пределах своих прав, чтобы не скомпилировать эту программу; фатальная ошибка для этой программы, IME, несоответствие. (Предупреждение, OTOH, прекрасно. Компилятор может предупредить о отсутствующих операторах возврата, странных наследованиях наследования, британском/американском написании в идентификаторах или расистских комментариях в строковых литералах, если он захочет, при условии, что он действительно компилирует действующие программы.)

Я полагаю, что ваша программа создает поведение undefined при запуске, так как вы безоговорочно выполняете функцию, которая не возвращает значение. Тем не менее, я не думаю, что оправдывает компилятор от собственно компиляции этой программы; для всего, что он знает, вы компилируете программу, копируете исполняемый файл на ленту и не смотрите на нее снова. Кроме того, я ожидаю, что если компилятор испустит ошибку для этой программы, она, скорее всего, испустит ошибку для программы, которая только называется bar() после проверки этого argc==1 и, безусловно, не будет в пределах прав UB компилятора.

Строго говоря, компилятор не должен соответствовать всем обстоятельствам, которые считаются соответствующими. Соответствующий компилятор просто должен иметь возможность компилировать любую действительную программу на С++. Поскольку вы можете скомпилировать эту программу без -Wall, можно утверждать, что GCC является совместимым без этого флажка. Удивительно, что включение предупреждений приведет к ошибкам несоответствия, хотя я бы склонялся к тому, чтобы характеризовать это как проблему соответствия в GCC.

+2
источник

Посмотрите другие вопросы по меткам или Задайте вопрос