https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123180
Bug ID: 123180
Summary: [16 Regression] -Wnonnull with
std::ranges::stable_sort
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: [email protected]
Target Milestone: ---
hi -
With a recent gcc trunk checkout (20251211) on a x86_64-pc-linux-gnu (fedora
42)
host, this source gets a -Wnonnull warning at -O3:
-------------------------------------------
#include <vector>
#include <algorithm>
struct M
{
int x() const;
};
void sort(std::vector<const M*>& v) {
auto cmp = [](const M* a, const M* b) { return a->x() > b->x(); };
std::ranges::stable_sort (v, cmp);
}
-------------------------------------------
$ g++ -c -std=c++20 -Wall -O3 x.cc
In file included from /usr/local/gcc/include/c++/16.0.0/bits/ranges_algo.h:39,
from /usr/local/gcc/include/c++/16.0.0/algorithm:65,
from x.cc:2:
In function ‘constexpr std::__conditional_t<_IsMove,
std::ranges::in_out_result<_Iter, _Out>, std::ranges::in_out_result<_Iter,
_Out> > std::ranges::__copy_or_move(_Iter, _Sent, _Out) [with bool _IsMove =
true; _Iter = const M**; _Sent = const M**; _Out = const M**]’,
inlined from ‘constexpr std::__conditional_t<_IsMove,
std::ranges::in_out_result<_Iter, _Out>, std::ranges::in_out_result<_Iter,
_Out> > std::ranges::__copy_or_move(_Iter, _Sent, _Out) [with bool _IsMove =
true; _Iter = __gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >;
_Sent = __gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Out =
const M**]’ at /usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:286:39,
inlined from ‘constexpr std::ranges::move_result<_Iter, _Out>
std::ranges::__move_fn::operator()(_Iter, _Sent, _Out) const [with _Iter =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Sent =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Out = const
M**]’ at /usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:366:37,
inlined from ‘_Iter1 std::ranges::__detail::__rotate_adaptive(_Iter1,
_Iter1, _Iter1, std::iter_difference_t<_Iter>, std::iter_difference_t<_Iter>,
_Iter2, std::iter_difference_t<_Iter>) [with _Iter1 =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Iter2 = const
M**]’ at /usr/local/gcc/include/c++/16.0.0/bits/ranges_algo.h:3686:30,
inlined from ‘void std::ranges::__detail::__merge_adaptive_resize(_Iter,
_Iter, _Iter, _Distance, _Distance, _Pointer, _Distance, _Comp) [with _Iter =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Distance =
long int; _Pointer = const M**; _Comp = _Comp_proj<sort(std::vector<const
M*>&)::<lambda(const M*, const M*)>, std::identity>]’ at
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algo.h:3763:37:
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:305:38: warning:
argument 1 null where non-null expected because argument 3 is nonzero
[-Wnonnull]
305 | __builtin_memmove(__result, __first,
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
306 | sizeof(_ValueTypeI) * __num);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:305:38: note: in a
call to built-in function ‘void* __builtin_memmove(void*, const void*, long
unsigned int)’
In function ‘constexpr std::__conditional_t<_IsMove,
std::ranges::in_out_result<_Iter, _Out>, std::ranges::in_out_result<_Iter,
_Out> > std::ranges::__copy_or_move(_Iter, _Sent, _Out) [with bool _IsMove =
true; _Iter = const M**; _Sent = const M**; _Out = const M**]’,
inlined from ‘constexpr std::__conditional_t<_IsMove,
std::ranges::in_out_result<_Iter, _Out>, std::ranges::in_out_result<_Iter,
_Out> > std::ranges::__copy_or_move(_Iter, _Sent, _Out) [with bool _IsMove =
true; _Iter = const M**; _Sent = const M**; _Out =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >]’ at
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:293:39,
inlined from ‘constexpr std::ranges::move_result<_Iter, _Out>
std::ranges::__move_fn::operator()(_Iter, _Sent, _Out) const [with _Iter =
const M**; _Sent = const M**; _Out = __gnu_cxx::__normal_iterator<const M**,
std::vector<const M*> >]’ at
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:366:37,
inlined from ‘_Iter1 std::ranges::__detail::__rotate_adaptive(_Iter1,
_Iter1, _Iter1, std::iter_difference_t<_Iter>, std::iter_difference_t<_Iter>,
_Iter2, std::iter_difference_t<_Iter>) [with _Iter1 =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Iter2 = const
M**]’ at /usr/local/gcc/include/c++/16.0.0/bits/ranges_algo.h:3688:22,
inlined from ‘void std::ranges::__detail::__merge_adaptive_resize(_Iter,
_Iter, _Iter, _Distance, _Distance, _Pointer, _Distance, _Comp) [with _Iter =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Distance =
long int; _Pointer = const M**; _Comp = _Comp_proj<sort(std::vector<const
M*>&)::<lambda(const M*, const M*)>, std::identity>]’ at
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algo.h:3763:37:
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:305:38: warning:
argument 2 null where non-null expected because argument 3 is nonzero
[-Wnonnull]
305 | __builtin_memmove(__result, __first,
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
306 | sizeof(_ValueTypeI) * __num);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:305:38: note: in a
call to built-in function ‘void* __builtin_memmove(void*, const void*, long
unsigned int)’
In function ‘constexpr std::__conditional_t<_IsMove,
std::ranges::in_out_result<_Iter, _Out>, std::ranges::in_out_result<_Iter,
_Out> > std::ranges::__copy_or_move(_Iter, _Sent, _Out) [with bool _IsMove =
true; _Iter = const M**; _Sent = const M**; _Out = const M**]’,
inlined from ‘constexpr std::__conditional_t<_IsMove,
std::ranges::in_out_result<_Iter, _Out>, std::ranges::in_out_result<_Iter,
_Out> > std::ranges::__copy_or_move(_Iter, _Sent, _Out) [with bool _IsMove =
true; _Iter = __gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >;
_Sent = __gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Out =
const M**]’ at /usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:286:39,
inlined from ‘constexpr std::ranges::move_result<_Iter, _Out>
std::ranges::__move_fn::operator()(_Iter, _Sent, _Out) const [with _Iter =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Sent =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Out = const
M**]’ at /usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:366:37,
inlined from ‘_Iter1 std::ranges::__detail::__rotate_adaptive(_Iter1,
_Iter1, _Iter1, std::iter_difference_t<_Iter>, std::iter_difference_t<_Iter>,
_Iter2, std::iter_difference_t<_Iter>) [with _Iter1 =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Iter2 = const
M**]’ at /usr/local/gcc/include/c++/16.0.0/bits/ranges_algo.h:3697:30,
inlined from ‘void std::ranges::__detail::__merge_adaptive_resize(_Iter,
_Iter, _Iter, _Distance, _Distance, _Pointer, _Distance, _Comp) [with _Iter =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Distance =
long int; _Pointer = const M**; _Comp = _Comp_proj<sort(std::vector<const
M*>&)::<lambda(const M*, const M*)>, std::identity>]’ at
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algo.h:3763:37:
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:305:38: warning:
argument 1 null where non-null expected because argument 3 is nonzero
[-Wnonnull]
305 | __builtin_memmove(__result, __first,
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
306 | sizeof(_ValueTypeI) * __num);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:305:38: note: in a
call to built-in function ‘void* __builtin_memmove(void*, const void*, long
unsigned int)’
In function ‘constexpr std::__conditional_t<_IsMove,
std::ranges::in_out_result<_Iter, _Out>, std::ranges::in_out_result<_Iter,
_Out> > std::ranges::__copy_or_move_backward(_Iter, _Sent, _Out) [with bool
_IsMove = true; _Iter = const M**; _Sent = const M**; _Out = const M**]’,
inlined from ‘constexpr std::__conditional_t<_IsMove,
std::ranges::in_out_result<_Iter, _Out>, std::ranges::in_out_result<_Iter,
_Out> > std::ranges::__copy_or_move_backward(_Iter, _Sent, _Out) [with bool
_IsMove = true; _Iter = const M**; _Sent = const M**; _Out =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >]’ at
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:419:48,
inlined from ‘constexpr std::ranges::move_backward_result<_Iter1, _Iter2>
std::ranges::__move_backward_fn::operator()(_Iter1, _Sent1, _Iter2) const [with
_Iter1 = const M**; _Sent1 = const M**; _Iter2 =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >]’ at
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:501:46,
inlined from ‘_Iter1 std::ranges::__detail::__rotate_adaptive(_Iter1,
_Iter1, _Iter1, std::iter_difference_t<_Iter>, std::iter_difference_t<_Iter>,
_Iter2, std::iter_difference_t<_Iter>) [with _Iter1 =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Iter2 = const
M**]’ at /usr/local/gcc/include/c++/16.0.0/bits/ranges_algo.h:3699:31,
inlined from ‘void std::ranges::__detail::__merge_adaptive_resize(_Iter,
_Iter, _Iter, _Distance, _Distance, _Pointer, _Distance, _Comp) [with _Iter =
__gnu_cxx::__normal_iterator<const M**, std::vector<const M*> >; _Distance =
long int; _Pointer = const M**; _Comp = _Comp_proj<sort(std::vector<const
M*>&)::<lambda(const M*, const M*)>, std::identity>]’ at
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algo.h:3763:37:
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:434:38: warning:
argument 2 null where non-null expected because argument 3 is nonzero
[-Wnonnull]
434 | __builtin_memmove(__result, __first,
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
435 | sizeof(_ValueTypeI) * __num);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/gcc/include/c++/16.0.0/bits/ranges_algobase.h:434:38: note: in a
call to built-in function ‘void* __builtin_memmove(void*, const void*, long
unsigned int)’
-------------------------------------------
The warnings are not seen with gcc 15.2.1.
Now, I don't think there's anything wrong with the input.
However, I think this warning may be pointing out an actual problem
in libstdc++.
In ranges-algo.h around line 2715 in __stable_sort_fn::operator(), we have
-------------------------------------------
_TmpBuf __buf(__first, ptrdiff_t((__last - __first + 1) / 2));
if (__buf._M_requested_size() == __buf.size()) [[likely]]
__detail::__stable_sort_adaptive(__first,
__first +
_DistanceType(__buf.size()),
__last, __buf.begin(),
__comp_proj);
else if (__buf.begin()) [[unlikely]]
__detail::__inplace_stable_sort(__first, __last, __comp_proj);
else
__detail::__stable_sort_adaptive_resize(__first, __last,
__buf.begin(),
_DistanceType(__buf.size()),
__comp_proj);
-------------------------------------------
The sense of the second arm of the if here looks backwards to me.
Indeed, if i change that line to
else if (!__buf.begin()) [[unlikely]]
then the warnings go away.
thanks!