clang говорит, что вызов функции void consteval не является постоянным выражением

clang (trunk) выдает ошибку для следующего кода:

consteval void f() {}

int main() 
{ 
    f();  // error: call to consteval function 'f' is not a constant expression
          // note: subobject of type 'void' is not initialized
}

в то время как gcc (trunk) компилирует это без ошибок.

Я считаю, что это, вероятно, ошибка clang, поскольку и gcc, и clang принимают этот код:

consteval int g() { return 42; }

int main() 
{ 
    g();  // ok
}

Вот код, с которым можно поиграть.

Так это ошибка clang, или код плохо сформирован, или есть ub, или что-то еще?


Изменить: я считаю, что было бы уместно указать, что clang позволяет вызывать f из других функций, если они также являются consteval. Он выдает ошибку только тогда, когда f вызывается из неконстевальных функций:

consteval int h() 
{ 
    f();       // ok
    return 42; 
}

демонстрация.


person cigien    schedule 11.08.2020    source источник
comment
Это работает, если f - constexpr? (при принудительном использовании constexpr, например constexpr int x = (f(), 5);)   -  person Dani    schedule 11.08.2020
comment
clang не заявляет, что пока что реализует consteval.   -  person Barry    schedule 11.08.2020
comment
@Dani Нет, выдает ту же ошибку.   -  person cigien    schedule 11.08.2020
comment
@Barry Верно, но у меня создалось впечатление, что какое-то время это было реализовано в магистрали. Значит, это просто неполная функция? Тем не менее, это странная ошибка.   -  person cigien    schedule 11.08.2020
comment
Тогда я бы сказал, что это ошибка компилятора. Обоснование, например, std::sort.   -  person Dani    schedule 11.08.2020
comment
Означает ли это, что сейчас clang не поддерживает сортировку constexpr? Это функция C ++ 20, так что им пока не нужно.   -  person Dani    schedule 11.08.2020
comment
@Dani Да, я не думаю, что constexpr sort еще поддерживается. Но какое здесь отношение?   -  person cigien    schedule 11.08.2020
comment
@Dani Какое отношение sort имеет к consteval? Это не consteval функция.   -  person Barry    schedule 11.08.2020
comment
BTW: В чем смысл consteval с функцией void?   -  person Klaus    schedule 11.08.2020
comment
@Klaus Ha, хороший вопрос, не подумал об этом: p Думаю, было бы полезно иметь именованную функцию, которая выполняет кучу static_asserts.   -  person cigien    schedule 11.08.2020
comment
@Klaus: функция все еще может изменять свои аргументы, если они объявлены в функции constexpr / eval. Например, std :: sort.   -  person Dani    schedule 11.08.2020
comment
@Barry: это про ситуацию в комментариях, где f - constexpr   -  person Dani    schedule 11.08.2020
comment
@ Дани: Отлично! Вот и все! Спасибо!   -  person Klaus    schedule 11.08.2020
comment
@Klaus Да, аргументы можно изменить. Я думал о функции void без аргументов, как в вопросе. Варианты использования для этого менее очевидны.   -  person cigien    schedule 11.08.2020


Ответы (2)


Это была ошибка Clang, которая появилась между версиями 10 и 11, и исправлена ​​ в прошлом месяце. Реализация consteval в Clang в основном, но не полностью, завершена, и эта ошибка возникла после того, как один из патчей добавил более полную поддержку consteval.

Подробности: точка входа верхнего уровня в вычислитель констант Clang проверяет, является ли результат допустимым результатом константного выражения - он проверяет, не содержит ли результат указателей на продолжительность автоматического хранения, временную или аналогичную. Но эта проверка никогда не обновлялась с учетом того, что void был буквальным типом, и отклоняла значения типа void как неинициализированные. Этого никогда не замечалось до добавления поддержки consteval, потому что все оценки констант верхнего уровня не относились к типам void.

person Richard Smith    schedule 21.09.2020

Я нашел окончательный вариант c ++ 20:

9.2.5 Спецификаторы constexpr и consteval [dcl.constexpr] (2) Спецификатор constexpr или consteval, используемый в объявлении функции, объявляет, что эта функция является функцией constexpr. Функция или конструктор, объявленные с помощью спецификатора consteval, называются анимированной функцией. Деструктор, функция распределения или функция освобождения не должны объявляться с помощью спецификатора consteval.

(3) Определение функции constexpr должно удовлетворять следующим требованиям:

3.1 его возвращаемый тип (если есть) должен быть буквальным типом;

а также

6.8 Типы [basic.types]

(10) Тип является буквальным типом, если он:

(10.1) резюме недействительно

...

Поскольку этот void является допустимым типом возврата для функции consteval.

person Klaus    schedule 11.08.2020
comment
Кажется, что если есть, то здесь недействительно. если есть, охватывает отсутствие у конструкторов и деструкторов возвращаемых типов. void f(); имеет тип возврата. «cv void» - это литерал введите, если он не подходит. - person Language Lawyer; 11.08.2020
comment
@LanguageLawyer: Спасибо за объяснение. Это делает void допустимым возвращаемым типом для функции conexpr / consteval. - person Klaus; 11.08.2020
comment
@LanguageLawyer как построить объект void? Это название он получил от K&R буквально за то, что ничего не значил. Я предполагаю, что архитектура clang терпит неудачу - person Swift - Friday Pie; 11.08.2020
comment
На самом деле, я не сомневаюсь, что определение f подходит. Вопрос в вызове f(), откуда взялась ошибка. Обратите внимание, что clang позволяет вызывать f из других consteval функций. демонстрация. - person cigien; 11.08.2020
comment
если какой-либо относится к отсутствию типов возвращаемых конструкторов и деструкторов Фактически, только отсутствие конструкторов, деструкторы не могут быть consteval. - person Language Lawyer; 11.08.2020
comment
Я немного отредактировал вопрос с возможно соответствующей информацией, если вы можете взглянуть. - person cigien; 11.08.2020
comment
@cigien: Я всегда могу вызывать функции consteval или constexpr из функций, отличных от consteval / constexpr. Я не читал ни о каких ограничениях в этом направлении. Обычно компилятор оптимизирует этот вызов. - person Klaus; 11.08.2020
comment
Нет, существуют языковые ограничения на вызов функций из определенных контекстов, которые не имеют ничего общего с оптимизацией компилятора. - person cigien; 12.08.2020