LLVM 库的 C++ API 生成了太多警告

C++ API for LLVM library generates too many warnings

我不确定我是唯一一个人还是很多人都有这个问题。

我遇到的问题是,即使是包含 LLVM headers 的简单代码,无论我在 main 函数中写了什么,我在编译代码时都会收到太多警告额外警告:

#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Verifier.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/IR/Instructions.h>

int main()
{
    return 0;
}

我通过使用 gccclang:

得到了这些警告

g++-9 -std=c++17 main.cpp -Wall -Wextra -I/usr/lib/llvm-9/include -c -o main.o

clang++-9 -std=c++17 main.cpp -Wall -Wextra -I/usr/lib/llvm-9/include -c -o main.o

主要是未使用的参数:

In file included from /usr/lib/llvm-9/include/llvm/IR/ConstantFolder.h:20,
                 from /usr/lib/llvm-9/include/llvm/IR/IRBuilder.h:24,
                 from main.cpp:1:
/usr/lib/llvm-9/include/llvm/IR/Constants.h: In member function ‘llvm::Value* llvm::ConstantData::handleOperandChangeImpl(llvm::Value*, llvm::Value*)’:
/usr/lib/llvm-9/include/llvm/IR/Constants.h:60:41: warning: unused parameter ‘From’ [-Wunused-parameter]
   60 |   Value *handleOperandChangeImpl(Value *From, Value *To) {
      |                                  ~~~~~~~^~~~
/usr/lib/llvm-9/include/llvm/IR/Constants.h:60:54: warning: unused parameter ‘To’ [-Wunused-parameter]
   60 |   Value *handleOperandChangeImpl(Value *From, Value *To) {
      |                                               ~~~~~~~^~
In file included from /usr/lib/llvm-9/include/llvm/IR/ConstantFolder.h:21,
                 from /usr/lib/llvm-9/include/llvm/IR/IRBuilder.h:24,
                 from main.cpp:1:
/usr/lib/llvm-9/include/llvm/IR/InstrTypes.h: In member function ‘bool llvm::CallBase::isFnAttrDisallowedByOpBundle(llvm::StringRef) const’:
/usr/lib/llvm-9/include/llvm/IR/InstrTypes.h:1913:47: warning: unused parameter ‘S’ [-Wunused-parameter]
 1913 |   bool isFnAttrDisallowedByOpBundle(StringRef S) const {
      |                                     ~~~~~~~~~~^
In file included from /usr/lib/llvm-9/include/llvm/IR/IRBuilder.h:33,
                 from main.cpp:1:
/usr/lib/llvm-9/include/llvm/IR/Instructions.h: In member function ‘llvm::BasicBlock* llvm::ReturnInst::getSuccessor(unsigned int) const’:
/usr/lib/llvm-9/include/llvm/IR/Instructions.h:2943:37: warning: unused parameter ‘idx’ [-Wunused-parameter]
 2943 |   BasicBlock *getSuccessor(unsigned idx) const {
      |                            ~~~~~~~~~^~~
...

我只是截断了这些警告。他们太多了。 当我打开 -Wconversion 时,问题变得更糟:

In file included from /usr/lib/llvm-9/include/llvm/Support/MathExtras.h:17,
                 from /usr/lib/llvm-9/include/llvm/ADT/SmallVector.h:19,
                 from /usr/lib/llvm-9/include/llvm/ADT/STLExtras.h:20,
                 from /usr/lib/llvm-9/include/llvm/ADT/StringRef.h:12,
                 from /usr/lib/llvm-9/include/llvm/ADT/StringMap.h:16,
                 from /usr/lib/llvm-9/include/llvm/Support/Host.h:16,
                 from /usr/lib/llvm-9/include/llvm/ADT/Hashing.h:48,
                 from /usr/lib/llvm-9/include/llvm/ADT/ArrayRef.h:12,
                 from /usr/lib/llvm-9/include/llvm/IR/IRBuilder.h:18,
                 from main.cpp:1:
/usr/lib/llvm-9/include/llvm/Support/SwapByteOrder.h: In function ‘uint16_t llvm::sys::SwapByteOrder_16(uint16_t)’:
/usr/lib/llvm-9/include/llvm/Support/SwapByteOrder.h:36:23: warning: conversion from ‘int’ to ‘uint16_t’ {aka ‘short unsigned int’} may change value [-Wconversion]
   36 |   uint16_t Hi = value << 8;
      |                 ~~~~~~^~~~
/usr/lib/llvm-9/include/llvm/Support/SwapByteOrder.h:37:23: warning: conversion from ‘int’ to ‘uint16_t’ {aka ‘short unsigned int’} may change value [-Wconversion]
   37 |   uint16_t Lo = value >> 8;
      |                 ~~~~~~^~~~
In file included from /usr/lib/llvm-9/include/llvm/ADT/STLExtras.h:20,
                 from /usr/lib/llvm-9/include/llvm/ADT/StringRef.h:12,
                 from /usr/lib/llvm-9/include/llvm/ADT/StringMap.h:16,
                 from /usr/lib/llvm-9/include/llvm/Support/Host.h:16,
                 from /usr/lib/llvm-9/include/llvm/ADT/Hashing.h:48,
                 from /usr/lib/llvm-9/include/llvm/ADT/ArrayRef.h:12,
                 from /usr/lib/llvm-9/include/llvm/IR/IRBuilder.h:18,
                 from main.cpp:1:
/usr/lib/llvm-9/include/llvm/ADT/SmallVector.h: In constructor ‘llvm::SmallVectorBase::SmallVectorBase(void*, size_t)’:
/usr/lib/llvm-9/include/llvm/ADT/SmallVector.h:45:35: warning: conversion from ‘size_t’ {aka ‘long unsigned int’} to ‘unsigned int’ may change value [-Wconversion]
   45 |       : BeginX(FirstEl), Capacity(TotalCapacity) {}
      |                                   ^~~~~~~~~~~~~
...

我也收到了 clang 的这些警告:

...
In file included from main.cpp:1:
In file included from /usr/lib/llvm-9/include/llvm/IR/IRBuilder.h:18:
In file included from /usr/lib/llvm-9/include/llvm/ADT/ArrayRef.h:12:
/usr/lib/llvm-9/include/llvm/ADT/Hashing.h:190:15: warning: implicit conversion changes signedness: 'const char' to 'uint8_t' (aka 'unsigned char') [-Wsign-conversion]
  uint8_t a = s[0];
          ~   ^~~~
/usr/lib/llvm-9/include/llvm/ADT/Hashing.h:191:15: warning: implicit conversion changes signedness: 'const char' to 'uint8_t' (aka 'unsigned char') [-Wsign-conversion]
  uint8_t b = s[len >> 1];
          ~   ^~~~~~~~~~~
/usr/lib/llvm-9/include/llvm/ADT/Hashing.h:192:15: warning: implicit conversion changes signedness: 'const char' to 'uint8_t' (aka 'unsigned char') [-Wsign-conversion]
  uint8_t c = s[len - 1];
          ~   ^~~~~~~~~~
...

这只是一个MWE。添加更多headers,我可以获得其他类型的警告,例如

/usr/lib/llvm-9/include/llvm/ADT/Twine.h:232:16: warning: ‘<anonymous>.llvm::Twine::RHS.llvm::Twine::Child::twine’ may be used uninitialized in this function [-Wmaybe-uninitialized]
           !RHS.twine->isBinary())
            ~~~~^~~~~

现在,我想知道LLVM是不是写错了?我总是打开所有警告并确保我的应用程序编译时出现 0 个警告。当我在使用 LLVM 时执行此操作时,我的代码的所有警告都被隐藏在 LLVM 之下。我不容易看到他们。通常人们的第一个建议是关闭那些警告开关。我坚决反对。我想为我的应用程序找到它们。我想到的替代解决方案是仅针对 LLVM 而不是针对我的应用程序关闭这些警告。这可能吗,尤其是在使用 CMake 时?

系统 header 文件导致警告的问题很常见。我真的无法判断那些 header 的作者是否“粗心”,但有一种相对简单的方法可以在包含 'offending' header 之前禁用特定警告s,然后在包含 'full' 警告后恢复它们。

对于 clang,您可以使用各种 #pragma diagnostic ... 行来执行此操作,如以下代码片段所示:

#if defined (__clang__)
#pragma clang diagnostic push // Saves current diagnostic settings
#pragma clang diagnostic ignored "-Wsign-conversion" // Ignore this warning
#pragma clang diagnostic ignored "-Wunused-parameter" // and this one...
    // ... Add similar lines for other warnings you wish to disable
#endif

// Now include the 'offending' headers ...
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Verifier.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/IR/Instructions.h>

#if defined(__clang__)
#pragma clang diagnostic pop // Restores the saved settings
#endif

我无法访问 GCC 编译器,但我 相信 可以使用非常相似的指令:只需将 GCC 替换为 clang发生这种情况的行。有关此类 #pragma 指令(针对 GCC 版本)的更多信息,请参见 here.

这取决于您的 GCC/clang/OS 安装。在 Fedora 32 上,它开箱即用,系统 gcc-10.2.1-1.fc32.x86_64 + 系统 clang-10.0.0-2.fc32.x86_64:

#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Verifier.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/IR/Instructions.h>

static void func(int val) {}

int main()
{
    func(42);
    return 0;
}

对于海湾合作委员会:

$ g++ -o Whosebugllvmwarnings Whosebugllvmwarnings.C $(llvm-config --cflags --libs) -std=c++17 -Wall -Wextra
Whosebugllvmwarnings.C: In function ‘void func(int)’:
Whosebugllvmwarnings.C:7:22: warning: unused parameter ‘val’ [-Wunused-parameter]
    7 | static void func(int val) {}
      |                  ~~~~^~~
$ _

叮当声:

$ clang++ -o Whosebugllvmwarnings Whosebugllvmwarnings.C $(llvm-config --cflags --libs) -std=c++17 -Wall -Wextra
Whosebugllvmwarnings.C:7:22: warning: unused parameter 'val' [-Wunused-parameter]
static void func(int val) {}
                     ^
1 warning generated.
$ _

如果你真的想要(你不想要)警告,即使是系统头文件,也可以使用 Wsystem-headers(对于 gcc 和 clang,它的工作方式相似):

$ clang++ -o Whosebugllvmwarnings Whosebugllvmwarnings.C $(llvm-config --cflags --libs) -std=c++17 -Wall -Wextra -Wsystem-headers
In file included from Whosebugllvmwarnings.C:1:
In file included from /usr/include/llvm/IR/IRBuilder.h:17:
In file included from /usr/include/llvm-c/Types.h:17:
In file included from /usr/include/llvm-c/DataTypes.h:28:
In file included from /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/cmath:42:
/usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/bits/cpp_type_traits.h:110:12: warning: keyword '__is_void' will be made available as an identifier for the remainder of the translation unit [-Wkeyword-compat]
    struct __is_void
           ^
...