GCC 不遵守 'pragma GCC diagnostic' 来消除警告

GCC does not honor 'pragma GCC diagnostic' to silence warnings

我们最近为一个项目启用了 -Wall。它在 GCC 为 4.7 或更高版本(或 Clang)时启用,因为我们可以使用 GCC diagnostic 来管理提升警告的输出。我们希望通过源代码管理它们,而不是通过命令行参数 。 (我们不想污染命令行,也不想让图书馆用户重新发现需要的东西)。

在 GCC 4.8 和 5.1 下,我们正在捕获在 -Wunused-variable-Wunused-value-Wunused-function-Wunknown-pragmas 的 GCC 诊断块中禁用的警告。两个 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 has the following guard in place to help manage that warning (only relevant parts are shown, but you can see everything from the GitHub link):

// 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" 也无济于事。终于在Clang下正常运行了

我也遇到了其他警告,例如 -Wunused-variable-Wunused-value-Wunused-function。我 真的 不想像建议的那样用潜在的重复项污染命令行。

如何使 GCC pragma diagnostic 机制按预期工作以在使用 -Wall 时消除 GCC 下的警告?


相关,如果你想复制它(它基于 GNUmakefile,不需要配置或自动工具):

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

编辑:我们签入了一个禁用 -Wall 除了 Clang 的补丁。如果您想重现旧行为,则:

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

这至少在 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 有关,但其中一条评论中的一个片段表明它可能适用于影响预处理器的所有变体(为了强调而略微修改):

The C++ parser lexes (and preprocesses) before handling the pragmas, whereas the C parser processes the pragmas as it sees them.

We must somehow parse these pragmas also in cp/parser.c:631. Maybe one can do something similar to what we do for cp_parser_initial_pragma, but within the loop and only handling pragma diagnostic. Surely, it will need some trial and error to get it right. If any of you wants to give it a try and need some help, just ask here or in the mailing list.

这就解释了为什么我们在 -Wuninitialized 中看不到同样的问题,因为它是在编译过程的后期检测到的,在预处理结束时 pragma 被激活之后。

因此,如果您想更及时地修复它(它是三年前提出的),我建议(就像我一样)麻烦 GCC bugzilla 站点以尝试获得一些曝光。