下面的代码是:
#include <iostream>
template<typename T>
struct A
{
T a;
T b;
static bool(*foo)(T, T);
};
template<>
bool(*A<int>::foo)(int, int) = [](int a, int b)->bool{ return a == b; };
struct B
{
int b;
};
template<typename T, typename U>
T bar(U(*func)(const int&)) { return func(23).b; }
int main()
{
A<int> a = {.a=1, .b=1};
std::cout << std::boolalpha << A<int>::foo(a.a, a.b) << std::endl;
std::cout << bar<int, B>([](const int& val) -> B { return {.b = val}; });
return 0;
}
在gcc 11.1下使用-Werror=nonnull -Og -fsanitize=undefined -std=c++20
标志编译时,它会根据lambda生成如下错误:
<source>:12:71: error: 'this' pointer is null [-Werror=nonnull]
(for更多详细信息,请参见https://godbolt.org/z/a4GsPW71E)
正如我所知,this = nullptr
在代码中是UB的一个生动的标记,但是我的代码看起来很不显眼。为了避免这个错误,你应该改变编译器的版本或者在代码中做一个微小的改变(例如,删除lambda的参数,或者模板,或者其他东西)。
有没有人知道这个错误的原因,gcc试图帮助我,或者它只是一个错误的编译器?
2条答案
按热度按时间qlvxas9a1#
下面是我能把你的例子简化到的最大限度:
https://godbolt.org/z/rbrczEbPx
我的猜测是
-fsanitize=undefined
向lambda添加了一些代码,检查lambda类型的operator()
中的this
,并且一些优化通过将lambda中的this
指针设置为nullptr
来完全删除lambda对象,因为它未被使用,这被-Werror=nonnull
捕获。但是,这是一个GCC错误。它不会出现在gcc-11.2或gcc-10中。作为一种解决方法,您可以如下所示替换代码:
或者只禁用该代码区域周围的
-Wnonnull
:这可能与此错误有关:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96003
ztmd8pv52#
我将称之为编译器错误。错误信息显然是无意义的:
:在静态成员函数'static constexpr bool A::::_FUN(int,int)'中::12:71:错误:“this”指针为空[-Werror=非空]
“静态成员函数”...“”this“指针为空”
我可以理解这里发生了什么。一个非捕获的lambda可以被转换成一个函数指针。lambda是一个对象,所以GCC内部有一个
this
指针是合理的,但是当operator(int,int)
,也就是_FUN
被转换成一个自由函数时,这个指针就没有意义了。