Issue 203719
Summary [clang] Incorrect -Wunneeded-member-function warning in C++20 mode with ranges library code
Labels
Assignees
Reporter pkl97
    This program triggers a -Wunneeded-member-function warning if define INCLUDE_EQUALS_OPERATOR is set (see https://godbolt.org/z/17Tneax4K):
```c++
#include <algorithm>
#include <compare>
#include <vector>

namespace {

#define INCLUDE_EQUALS_OPERATOR

// The struct is intentionally not declared in any header. It is local to this translation unit.
struct Foo
{
 std::strong_ordering operator<=>(const Foo& p_rhs) const; // not defaulted
#if defined(INCLUDE_EQUALS_OPERATOR)
    bool operator==(const Foo& p_rhs) const; // not defaulted
#endif

    int m_value;
};

std::strong_ordering Foo::operator<=>(const Foo& p_rhs) const
{
    return m_value <=> p_rhs.m_value;
}

#if defined(INCLUDE_EQUALS_OPERATOR)
bool Foo::operator==(const Foo& p_rhs) const
{
    return m_value == p_rhs.m_value;
}
#endif

} // namespace

int main()
{
    std::vector<Foo> v;
 std::ranges::sort(v); // requires operator==() through concept satisfaction
 return 0;
}
```

The compiler deduces that operator==() is not used and therefore not needed:

```shell
<source>:26:11: warning: member function 'operator==' is not needed and will not be emitted [-Wunneeded-member-function]
   26 | bool Foo::operator==(const Foo& p_rhs) const
      |           ^~~~~~~~
1 warning generated.
```

However, if the define INCLUDE_EQUALS_OPERATOR is commented out (see https://godbolt.org/z/ooYxqa1fM) then the warning transforms into an error:
```
<source>:37:5: error: no matching function for call to object of type 'const __sort_fn'
   37 |     std::ranges::sort(v); // requires operator==() through concept satisfaction
      | ^~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/17.0.0/../../../../include/c++/17.0.0/bits/ranges_algo.h:2507:7: note: candidate template ignored: constraints not satisfied [with _Range = std::vector<Foo> &, _Comp = ranges::less, _Proj = identity]
 2507 | operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
      | ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/17.0.0/../../../../include/c++/17.0.0/bits/ranges_algo.h:2505:16: note: because 'sortable<iterator_t<std::vector<(anonymous namespace)::Foo, std::allocator<(anonymous namespace)::Foo> > &>, std::ranges::less, std::identity>' evaluated to false
 2505 |       requires sortable<iterator_t<_Range>, _Comp, _Proj>
      | ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/17.0.0/../../../../include/c++/17.0.0/bits/iterator_concepts.h:971:10: note: because 'indirect_strict_weak_order<std::ranges::less, projected<__gnu_cxx::__normal_iterator<(anonymous namespace)::Foo *, std::vector<(anonymous namespace)::Foo, std::allocator<(anonymous namespace)::Foo> > >, std::identity>>' evaluated to false
  971 |       && indirect_strict_weak_order<_Rel, projected<_Iter, _Proj>>;
      | ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/17.0.0/../../../../include/c++/17.0.0/bits/iterator_concepts.h:755:10: note: because 'strict_weak_order<std::ranges::less &, __indirect_value_t<std::__detail::__projected<__gnu_cxx::__normal_iterator<(anonymous namespace)::Foo *, std::vector<(anonymous namespace)::Foo, std::allocator<(anonymous namespace)::Foo> > >, std::identity>::__type>, __indirect_value_t<std::__detail::__projected<__gnu_cxx::__normal_iterator<(anonymous namespace)::Foo *, std::vector<(anonymous namespace)::Foo, std::allocator<(anonymous namespace)::Foo> > >, std::identity>::__type>>' evaluated to false
  755 |       && strict_weak_order<_Fn&, __indirect_value_t<_I1>, __indirect_value_t<_I2>>
      | ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/17.0.0/../../../../include/c++/17.0.0/concepts:406:33: note: because 'relation<std::ranges::less &, (anonymous namespace)::Foo &, (anonymous namespace)::Foo &>' evaluated to false
  406 |     concept strict_weak_order = relation<_Rel, _Tp, _Up>;
      | ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/17.0.0/../../../../include/c++/17.0.0/concepts:397:9: note: because 'predicate<std::ranges::less &, (anonymous namespace)::Foo &, (anonymous namespace)::Foo &>' evaluated to false
  397 |       = predicate<_Rel, _Tp, _Tp> && predicate<_Rel, _Up, _Up>
      | ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/17.0.0/../../../../include/c++/17.0.0/concepts:391:25: note: because 'regular_invocable<std::ranges::less &, (anonymous namespace)::Foo &, (anonymous namespace)::Foo &>' evaluated to false
  391 | concept predicate = regular_invocable<_Fn, _Args...>
      | ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/17.0.0/../../../../include/c++/17.0.0/concepts:387:33: note: because 'invocable<std::ranges::less &, (anonymous namespace)::Foo &, (anonymous namespace)::Foo &>' evaluated to false
  387 |     concept regular_invocable = invocable<_Fn, _Args...>;
      | ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/17.0.0/../../../../include/c++/17.0.0/concepts:383:25: note: because 'is_invocable_v<std::ranges::less &, (anonymous namespace)::Foo &, (anonymous namespace)::Foo &>' evaluated to false
  383 |     concept invocable = is_invocable_v<_Fn, _Args...>;
      | ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/17.0.0/../../../../include/c++/17.0.0/bits/ranges_algo.h:2483:7: note: candidate function template not viable: requires at least 2 arguments, but 1 was provided
 2483 |       operator()(_Iter __first, _Sent __last,
 |       ^          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2484 | _Comp __comp = {}, _Proj __proj = {}) const
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
```

The explanation seems to be that std::ranges::sort(v) by default uses std::ranges::less which requires (via a C++20 concept) std::totally_ordered_with and this in turn demands std::equality_comparable. So according to the concept restrictions operator==() is needed, but the warning does not seem to be considering this fact. It only focuses on operator==() being unused in the code itself, which is true.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to