| 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