GCC не соблюдает "прагматическую диагностику GCC", чтобы отключить предупреждения

Недавно мы включили -Wall для проекта. Он включен, когда GCC находится на уровне 4.7 или выше (или Clang), потому что мы можем использовать GCC diagnostic для управления выходом с повышенными предупреждениями. Мы хотим управлять ими из исходного кода и не с помощью аргументов командной строки. (Мы не хотим загрязнять командную строку или попросить пользователей библиотеки заново открыть то, что необходимо).

В GCC 4.8 и 5.1 мы обнаруживаем предупреждения, которые были отключены в диагностическом блоке GCC для -Wunused-variable, -Wunused-value, -Wunused-function и -Wunknown-pragmas. Оба GCC принимают -fopenmp, и оба определяют _OPENMP в ответ на него, поэтому я уверен, что мы не должны видеть -Wunknown-pragmas в ответ на #prgam omp ... (он отключен, но он не неизвестен).

g++ -DNDEBUG -g2 -O3 -Wall -march=native -pipe -c nbtheory.cpp
nbtheory.cpp:655:0: warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
  #pragma omp parallel
 ^
nbtheory.cpp:656:0: warning: ignoring #pragma omp sections [-Wunknown-pragmas]
   #pragma omp sections
 ^
...

В этом конкретном случае file nbtheroy.cpp имеет следующую защиту, чтобы помочь справиться с этим предупреждением (отображаются только соответствующие части, но вы можете видеть все: ссылка GitHub):

// Defines GCC_DIAGNOSTIC_AWARE if GCC 4.7 or above.
#include <misc.h>
...

#if GCC_DIAGNOSTIC_AWARE
# pragma GCC diagnostic ignored "-Wunknown-pragmas"
#endif

...
Integer ModularRoot(const Integer &a, const Integer &dp, const Integer &dq,
                    const Integer &p, const Integer &q, const Integer &u)
{
    Integer p2, q2;
    #pragma omp parallel
        #pragma omp sections
        {
            #pragma omp section
                p2 = ModularExponentiation((a % p), dp, p);
            #pragma omp section
                q2 = ModularExponentiation((a % q), dq, q);
        }
    return CRT(p2, p, q2, q, u);
}
...

Поскольку файл *.cpp (его эффективная единица перевода), не выполнить #pragma GCC diagnostic push в начале и #pragma GCC diagnostic pop в конце. (Мы делаем это для файлов заголовков, которые включены, однако). (Мы также пытались это сделать, но это не помогло).

И вот GCC_DIAGNOSTIC_AWARE (из misc.h):

// Used to suppress some warnings in some header and implementation files.
//   Some platforms, like CentOS and OpenBSD, use old compilers that don't understand -Wno-unknown-pragma.
#define GCC_DIAGNOSTIC_AWARE ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) || defined(__clang__))

Я знаю, что охранник работает, потому что добавление в блок #error вызывает ошибку. Кроме того, комментирование охранника и вызов #pragma GCC diagnostic ignored "-Wunknown-pragmas" не помогают. Наконец, он отлично работает под Кланом.

Я также испытываю это для других предупреждений, таких как -Wunused-variable, -Wunused-value и -Wunused-function. Я действительно не хочу загрязнять командную строку, как предполагалось, с помощью потенциального дубликата.

Как мне заставить механизм GCC pragma diagnostic работать как ожидается, чтобы отключить предупреждения в GCC при использовании -Wall?


Связанный, если вы хотите воспроизвести его (основанный на GNUmakefile и не требующий конфигураций или autotools):

git clone https://github.com/weidai11/cryptopp.git cryptopp-warn
cd cryptopp-warn
make

EDIT: мы отметили патч, который отключает -Wall, за исключением Clang. Если вы хотите воспроизвести старое поведение, то:

git clone https://github.com/weidai11/cryptopp.git cryptopp-warn
cd cryptopp-warn
export CXXFLAGS="-g2 -O3 -DNDEBUG -Wall"
make

Ответ 1

Похоже, это ошибка в gcc. Следующий код:

#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wuninitialized"

int fn(void) {
    #pragma xyzzy
    int x;
    return x;
}

int main (void) {
    return fn();
}

не имеет проблем с игнорированием неинициализированного значения x, но все еще жалуется на прагму (без прагмы uninitialized, она генерирует предупреждение для x, как и следовало ожидать).

Если вы измените параметры командной строки на -Wall -Wno-unknown-pragmas, то она игнорирует ее просто отлично. Это хорошо для вашего конкретного случая, так как вы хотите, чтобы он применялся по всей вашей единице перевода, но он не позволит мелкомасштабному управлению, которое вы получите от метода #pragma (если он сработает).


Я пошел, чтобы поднять отчет об ошибке на GCC, но обнаружил, что он уже существует (# 53431).

В то время как эта конкретная ошибка связана с -Wundef, фрагмент в одном из комментариев указывает, что он, вероятно, относится ко всем вариантам, влияющим на препроцессор (слегка модифицированный для выделения):

Лексы синтаксического анализатора С++ (и препроцессы) перед обработкой прагм, тогда как C-парсер обрабатывает прагмы по мере их просмотра.

Мы должны каким-то образом проанализировать эти прагмы и в cp/parser.c:631. Возможно, можно сделать что-то похожее на то, что мы делаем для cp_parser_initial_pragma, но внутри цикла и обрабатывать только диагностику pragma. Разумеется, для правильной работы потребуется пробная версия и ошибка. Если кто-то из вас захочет попробовать и вам понадобится помощь, просто спросите здесь или в списке рассылки.

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

Итак, если вы хотите, чтобы он был исправлен более своевременно (он был поднят более трех лет назад), я бы предложил (как я), чтобы направить сайт GCC bugzilla, чтобы попытаться получить некоторую информацию.