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!

Reply via email to