On Fri, 14 Feb 2025 at 03:03, Andrew Pinski <quic_apin...@quicinc.com> wrote:
>
> The code example here does:
> ```
> if (begin == end) __builtin_unreachable();
> std::list nl(begin, end);
>
> for (auto it = nl.begin(); it != nl.end(); it++)
> {
> ...
> }
> /* Remove the first element of the list. */
> nl.erase(nl.begin());
> ```
>
> And we get a warning because because we jump threaded the case were we
> think the list was empty from the for loop BUT we populated it without
> an empty array. So can help the compiler here by adding that after 
> initializing
> the list with non empty array, that the list will not be empty either.
>
> This is able to remove the -Wfree-nonheap-object warning in the first reduced
> testcase (with the fix for `begin == end` case added) in the PR 118865; the 
> second
> reduced testcase has been filed off as PR 118867.
>
> Bootstrapped and tested on x86_64-linux-gnu.
>
> libstdc++-v3/ChangeLog:
>
>         PR libstdc++/118865
>         * include/bits/stl_list.h (_M_initialize_dispatch): Add an
>         unreachable if the iterator was not empty that the list will
>         now be not empty.
>
> Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com>
> ---
>  libstdc++-v3/include/bits/stl_list.h | 6 ++++++
>  1 file changed, 6 insertions(+)
>
> diff --git a/libstdc++-v3/include/bits/stl_list.h 
> b/libstdc++-v3/include/bits/stl_list.h
> index be33eeb03d4..f987d8b9d0a 100644
> --- a/libstdc++-v3/include/bits/stl_list.h
> +++ b/libstdc++-v3/include/bits/stl_list.h
> @@ -2384,12 +2384,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>         _M_initialize_dispatch(_InputIterator __first, _InputIterator __last,
>                                __false_type)
>         {
> +         bool __notempty = __first != __last;
>           for (; __first != __last; ++__first)
>  #if __cplusplus >= 201103L
>             emplace_back(*__first);
>  #else
>             push_back(*__first);
>  #endif
> +        if (__notempty)
> +          {
> +            if (begin() == end())
> +              __builtin_unreachable();
> +          }

Would there be any benefit in also telling the compiler that when
first==last that the resulting list *is* empty?

so e.g.

  const bool __empty = __first == __last;
  // loop
  if (__empty != (begin() == end()))
    __builtin_unreachable();


Testing first == last twice for the first iteration bugs me a little,
but I assume that can be optimized? Or should we use a do-while?

          if (__first != __last)
            {
              do
                {
#if __cplusplus >= 201103L
                  emplace_back(*__first);
#else
                  push_back(*__first);
#endif
                } while (++__first != __last);
              if (begin() == end())
                __builtin_unreachable();
            }

Reply via email to