Re[2]: концепты?
От: Кодт Россия  
Дата: 05.04.23 19:18
Оценка: 9 (1) +1
Здравствуйте, Sm0ke, Вы писали:

В 20 (ну и в 23) стандарте есть недосказанность, а в C++ ABI популярных компиляторов (gcc / clang / msvc), соответственно, есть БАГ, эксплуатирующий эту недосказанность.
А именно, ограничения (концепты и requires) не попадают в декорированные имена.

Из-за этого можно написать well-formed программу, в которой сам же компилятор нарушит ODR: даст двум разным функциям один и тот же символ линковки.
А потом сойдёт с ума сам (если проинлайнит) или сведёт с ума линкер.

template<class T> void foo() { printf("1"); }

template<class T> void bar() { foo<T>(); }  // в этой точке видна только foo #1, поэтому она и вызовется

template<class T> void foo() requires true { printf("2"); }

template<class T> void buz() { foo<T>(); }  // функция с ограничением имеет приоритет, поэтому вызовется foo #2

int main() {
  bar<void>();
  buz<void>();
}
// для разнообразия, попробуйте разнести объявления и определения foo
// и перетащить определения выше-ниже точки инстанцирования, то есть, main().


...думаете вы!

И это, я хочу заметить, дистилированный пример.
Не дистиллированный бахнул, к счастью, не в продакшене, а в домашней работе у студента. У меня глаза вытекли, прежде чем я локализовал проблему.

Мейнтейнеры gcc сперва два года отбивались, говоря, что это ill-formed no diagnostics required и чего вы хотите, а потом взяли паузу на год и вот буквально месяц или два назад признали, что это баг.

А поскольку этот баг затрагивает спецификацию ABI, то его исправление приведёт к поломке огромного количества уже скомпилированных библиотек.
Так что, тут хоть закапывай, хоть выкапывай стюардессу, но раньше 2026 года он исправлен не будет.

Ну и кстати, возвращаясь к исходной теме про шаблоны.
MSVC по этим граблям сходил в 1998 году, когда ещё концептов не было.
Разработчики компилятора верили, что параметры шаблона всегда влияют на сигнатуру функции. (А иначе зачем нужно было шаблон писать? Г — Логика!)
template<class T> void foo();  // тип функции - один и тот же: void()

int main() {
  foo<int>();
  foo<char>(); // фигушки, линкер всё равно возьмёт foo<int>
}

и исправили его в 2005 году.
А до того народ лайфхачил как мог: добавлял невидимые аргументы, засовывал функции внутрь шаблона класса.

Но микрософту было хорошо, они хозяева своей экосистемы, взяли и заявили о несовместимости MSVC 7 и 8, пересобрали все виндовые библиотеки, и готово.

А гусь со шлангом так уже не могут!
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.