[libcxx-commits] [libcxx] [libc++] Avoid -Wzero-as-null-pointer-constant in operator<=> (PR #79465)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jan 25 12:35:20 PST 2024
================
@@ -30,14 +30,16 @@ class partial_ordering;
class weak_ordering;
class strong_ordering;
-template <class _Tp, class... _Args>
-inline constexpr bool __one_of_v = (is_same_v<_Tp, _Args> || ...);
-
struct _CmpUnspecifiedParam {
- _LIBCPP_HIDE_FROM_ABI constexpr _CmpUnspecifiedParam(int _CmpUnspecifiedParam::*) noexcept {}
-
- template <class _Tp, class = enable_if_t<!__one_of_v<_Tp, int, partial_ordering, weak_ordering, strong_ordering>>>
- _CmpUnspecifiedParam(_Tp) = delete;
+ // If anything other than a literal 0 is provided, the behavior is undefined by the Standard.
+ //
+ // We handle this by making this function consteval and making the program ill-formed if
+ // a value other than 0 is provided. This technically also accepts things that are not
+ // literal 0s like `1 - 1`. The alternative is to use the fact that a pointer can be
+ // constructed from literal 0, but this conflicts with `-Wzero-as-null-pointer-constant`.
+ template <class _Tp, class = __enable_if_t<is_same_v<_Tp, int> > >
+ _LIBCPP_HIDE_FROM_ABI consteval _CmpUnspecifiedParam(_Tp __zero) noexcept _LIBCPP_DIAGNOSE_ERROR(
+ __zero != 0, "Only literal 0 is allowed as the operand of a comparison with one of the ordering types") {}
----------------
ldionne wrote:
@cor3ntin This is really tricky. I can use `__diagnose_if__`, however in that case I really want to use `__enable_if` instead of `requires same_as`. Indeed, it seems that Clang evaluates those two "constraints" at different times, and the `_LIBCPP_DIAGNOSE_IF` condition (`__zero != 0`) is evaluated even when I pass something that's not an `int` if I use `requires same_as`.
So for example, I have a test case where I check that `strong_ordering == nullptr` doesn't compile (because there's no viable overload). If I use `requires same_as`, I also get a warning diagnostic because I am using 0 as a null pointer constant in the diagnose-if condition `__zero != 0`, where `__zero` is of type `nullptr_t`. That means I have to jump through hoops to either disable the diagnostic here or add an `expected-warning` in the test, but I don't want to do that since it's way too subtle.
Also, another point I want to raise about moving to `__diagnose_if__` is that we won't provide a diagnostic on GCC anymore. I think that's reasonable, but it's worth taking into account.
So IMO the patch in its current state goes for the best balance of simplicity, quality of implementation and maintainability.
https://github.com/llvm/llvm-project/pull/79465
More information about the libcxx-commits
mailing list