I've got the following code:
#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;
}
Being compiled with -Werror=nonnull -Og -fsanitize=undefined -std=c 20
flags under gcc 11.1 it produces a error per lambda like:
<source>:12:71: error: 'this' pointer is null [-Werror=nonnull]
(for more details see https://godbolt.org/z/a4GsPW71E)
As I know, this = nullptr
is a vivid marker of UB in the code, however my code looks pretty inconspicuous. To avoid the error you should either change version of compiler or make a slight change in the code (e.g. remove lambda's parameter, or template, or something else).
Does anyone know the reason of this errors, does gcc try to help me or it is just a bug in the compiler?
CodePudding user response:
Here is the most I can simplify your example to:
// g -11 -Werror=nonnull -Og -fsanitize=undefined
// (Or any level of optimization other than -O0)
bool(*bar)(int) = [](int) { return true; };
https://godbolt.org/z/rbrczEbPx
<source>: In static member function 'static constexpr bool<lambda(int)>::_FUN(int)': <source>:1:42: error: 'this' pointer is null [-Werror=nonnull] 1 | bool(*bar)(int) = [](int) { return true; }; | ^ <source>:1:19: note: in a call to non-static member function '<lambda(int)>' 1 | bool(*bar)(int) = [](int) { return true; }; | ^ cc1plus: some warnings being treated as errors
My guess is that -fsanitize=undefined
adds some code to the lambda checking something with the this
in the lambda type's operator()
, and some optimization removes the lambda object entirely with something that sets the this
pointer in the lambda to nullptr
since it is unused, which is caught by -Werror=nonnull
.
But yes, this is a GCC bug. It does not appear in gcc-11.2 nor in gcc-10. As a workaround, you can replace your code like so:
template<>
bool(*A<int>::foo)(int, int) = [](int a, int b)->bool{ return a == b; };
// becomes
inline auto A_foo_int_fn(int a, int b)->bool{ return a == b; }
template<>
bool(*A<int>::foo)(int, int) = A_foo_int_fn;
Or just disable -Wnonnull
around that region of code:
#if __GNUC__ == 11 && __GNUC_MINOR__ == 1
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
#endif
template<>
bool(*A<int>::foo)(int, int) = [](int a, int b)->bool{ return a == b; };
#if __GNUC__ == 11 && __GNUC_MINOR__ == 1
#pragma GCC diagnostic pop
#endif
This may be related to this bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96003
CodePudding user response:
I'm going to call this a compiler bug. The error message is obvious nonsense:
: In static member function 'static constexpr bool A::::_FUN(int, int)': :12:71: error: 'this' pointer is null [-Werror=nonnull]
"static member function" ... "'this' pointer is null".
I can sort of understand what happens here. A non-capturing lambda can be converted to a function pointer. The lambda is an object, so GCC reasonably has a this
pointer internally, but that pointer stops making sense when the operator(int,int)
aka _FUN
is converted to a free function.