clang++ features
Недавно тут вышел clang-2.8,
в котором таки пофиксили зарерпорчееный мной
баг про -fno-rtti и try/catch.
Это должно было позволить собрать с помощью clang++ большой C++ проект на работе.
clang++ споймал пару прикольных подозрительных кусков кода (все примеры - реальные):
- Использование логических (
|,&) операций вместо булевых (||,&&):
int CheckFileMask (const char * lpPath)
{
int result = CheckPathName (lpPath);
// Что-то делается ...
return result || 0x00000002;
}
// ...
bool SetDOSMask (char * lpMask)
{
// Что-то делается ...
int result = CheckFileMask (lpMask);
if( result && 0x00000001 != 0 )
{
// обрабатываем бит '0'
}
if( result && 0x00000002 != 0 )
{
// обрабатываем бит '1'
}
return result >= 0;
}Clang говорит:
use of logical || with constant operand; switch to bitwise | or remove constant
[-Wconstant-logical-operand]
return result || 0x00000002;
исправляем:
int CheckFileMask (const char * lpPath)
{
int result = CheckPathName (lpPath);
// Что-то делается ...
return result | 0x00000002;
}
// ...
bool SetDOSMask (char * lpMask)
{
// Что-то делается ...
int result = CheckFileMask (lpMask);
if (result & 0x00000001)
{
// обрабатываем бит '0'
}
if (result & 0x00000002)
{
// обрабатываем бит '1'
}
return result >= 0;
}- Неиспользуемый результат в выражении:
Оригинал:
while( ( * lpTmp == ' ' ) || ( * lpTmp == '\t' ) ) * lpTmp ++;Предупреджение:
boot/emucfg.cpp:244:56: warning: expression result unused [-Wunused-value]
while( ( * lpTmp == ' ' ) || ( * lpTmp == '\t' ) ) * lpTmp ++;
^ ~~~~~~~~
Исправляем:
while( ( * lpTmp == ' ' ) || ( * lpTmp == '\t' ) ) lpTmp ++;Было еще несколько красивых ошибок типизации, про которые лень писать.
- И самое интересное:
clang++правильно реализуетADL(argument dependent lookup), в отличие отg++.
Рассмотрим пример из бага, который я завел и тут же огрёб:
template<typename T> struct my_T {
my_T() {
my_foo ((const T *)0);
}
};
struct User {
User(); // explicit c-tor
my_T<char> t;
};
// we specialize my_foo for 'const char *'
static void my_foo (const char *) {}
User::User() { }
int main() {
User u;
return 0;
}Этот код g++ собирает, а clang++ - нет:
a.cc:4:9: error: use of undeclared identifier 'my_foo'
my_foo ((const T *)0);
^
a.cc:16:7: note: in instantiation of member function 'my_T<char>::my_T' requested here
User::User() { }
Внимательно читаем по ссылке.
Читаем еще раз!
Тут мы видим, что:
my_foo()в шаблоне явно зависит от параметра шаблона- значит имя является зависимым
- то есть его поиск производится в точке инстанцирования (определении конструктора
User::User()) - значит
my_foo()должно находиться при инстанцировании
А вот и нет! 4. пункт является верным только для типов, находящихся в пространстве имён my_T или пространстве
имён точки инстанцирования.
Но(!) встроенные типы(int, char, etc.) находятся в “нигде” (ни в каком из пространств имён)
и, как следствие, не подлежат поиску в ADL при специализации (это текущая формулировака поиска Кёнига
в стандарте). Вот если бы я вместо char объявил свой тип - всё было бы хорошо:
template<typename T> struct my_T {
my_T() {
my_foo ((const T *)0);
}
};
struct myO {};
struct User {
User(); // explicit c-tor
my_T<myO> t;
};
static void my_foo (const myO *) {}
User::User() { }
int main() {
User u;
return 0;
}g++ с таким положением дел не согласен и считает это
ошибкой в стандарте.
Правда, его в этом никто не поддерживает уже N лет. clang++ считает, что стандарту
10 лет, формулировка не менялась и по сему можно реализовать в точности с формулировкой:
you'll need to move the declaration up, or instantiate my_T with a non-builtin type (so that
argument-dependent lookup can find my_foo in the namespace of that type)
so builtin types are special?
not special, really; they have no "associated namespaces", i.e., there's nowhere for the compiler to look
at instantiation time
do coercions work in such case? Will 'static void my_foo(const void *) {}' for my user's types?
implicit conversions do work
static functions might not, though; I'd have to check the standard
the C++ DR in question is at http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#225 ,
and apparently hasn't been touched in 10 years. me, I'll stick with what the standard says :)
Для достижения портабельности придется декларацию my_foo() вытаскивать раньше шаблонного кода.
Спасибо dgregor на oftc/#llvm и Andrew Pinski в
gcc bugzilla за разьяснения.