понедельник, 5 сентября 2022 г.

[prog.c++] Давненько не сталкивался с неспособностью компилятора переварить наш C++ный код...

Готовлю к релизу небольшое обновление для RESTinio. Там суть в том, что в fmtlib есть возможность контроля за форматной строкой в compile-time. Для этого, когда мы находимся в рамках стандартов C++11/14/17, требуется помещать форматную строку внутрь макроса FMT_STRING:

fmt::print(FMT_STRING("The answer is {}\n"), 42);

Фокус в том, что макрос FMT_STRING должен применяться когда задан символ препроцессора FMT_ENFORCE_COMPILE_STRING. Если этот символ не задан, то форматная строка должна быть обычным строковым литералом.

Поскольку RESTinio -- это библиотека, которая может быть задействована в разных проектах с разными параметрами компиляции, то потребовалось модифицировать код RESTinio так, чтобы все было нормально и когда FMT_ENFORCE_COMPILE_STRING определен, и когда FMT_ENFORCE_COMPILE_STRING не определен.

Вроде как все сделал еще три недели назад, но приступить к подготовке релиза выдалась возможность только сейчас. Заодно оказалось, что fmtlib обновился до 9.1.0, поэтому я решил проверить RESTinio еще раз, уже с более свежей fmtlib.

И тут-то и оказалось, что в режиме C++20 и FMT_ENFORCE_COMPILE_STRING пара штатных тестов и один пример не компилируются clang-14.

Компилятор clang-14 как-то матерно ругался вот на такие строчки в одном из тестов (раз и два). Мол, какой-то из dependent type где-то в нутрях fmtlib не определен. А где и какой непонятно.

Пришлось несколько часов курить бамбук, пробовая и так, и сяк. Особенно удивляясь тому, что gcc-11 проглатывает этот же код нормально. Да и сам clang-14 похожий код в других местах вполне себе компилирует.

Лучик света забрежжил, когда я закомментировал вызов fmt::format на самом глубоком уровне вложенности (вот здесь).

Оказалось, что оставшийся вызов fmt::format после этого успешно скомпилировался, хотя до этого clang на него ругался.

Тут-то до меня дошло, что скорее всего имеет место какой-то глюк компилятора clang, который проявляется на слишком большом уровне вложенности лямбд.

Вынес часть функционала в отдельную вспомогательную функцию (делай раз, делай два) и...

Вуаля! Все скомпилировалось.

Морали не будет. Но будет озвучен вопрос, который меня серьезно озаботил: ну ладно, я-то давно люблюсь с C++ и C++ными компиляторами, падения с internal compiler error встречал неоднократно (к счастью, в последние годы все реже и реже)... А вот что было бы, если бы на моем месте был человек менее опытный? Который бы реально полез бы в потроха fmtlib чтобы разобраться что там за dependent type не определен... Вот сколько бы он времени на это убил бы?

Комментариев нет: