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

问题描述

我不确定我是不是唯一的人,或者这是很多其他人的问题。

我遭受的困扰是,即使是一个简单的包含LLVM标头的代码,无论我在主函数中编写了什么内容,在编译带有额外警告的代码时,我都会收到太多警告:

#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 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 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。添加更多标头,我可以获得其他类型的警告,例如

/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时是否可能?

解决方法

引起警告的系统头文件的问题很常见。对于我来说,并不是真的要判断这些标头的作者是否“粗心”,但是有一种相对简单的方法可以先禁用特定警告,然后再包含“令人反感”标头,然后在出现“标头”后恢复您的“完整”警告被包括在内。

对于 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。可以在here中找到有关此类#pragma指令(对于GCC版本)的更多信息。

,

这取决于您的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;
}

对于GCC:

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

对于c声:

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

如果您确实希望(也不希望这样做)甚至对于系统标头也使用Wsystem-headers(对于gcc和clang来说,它们的工作方式都相似):

$ clang++ -o stackoverflowllvmwarnings stackoverflowllvmwarnings.C $(llvm-config --cflags --libs) -std=c++17 -Wall -Wextra -Wsystem-headers
In file included from stackoverflowllvmwarnings.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
           ^
...