问题描述
我不确定我是不是唯一的人,或者这是很多其他人的问题。
我遭受的困扰是,即使是一个简单的包含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;
}
我可以通过使用gcc
或clang
来得到这些警告:
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
^
...