Change OnlyLiteralZero to not trigger modernize-use-nullptr

PiperOrigin-RevId: 521133781
Change-Id: I1334ea683bc01ef9b1b9800d6681e29dd2a1ec55
diff --git a/absl/types/compare.h b/absl/types/compare.h
index 1a965e9..2b89b69 100644
--- a/absl/types/compare.h
+++ b/absl/types/compare.h
@@ -36,6 +36,7 @@
 #include <type_traits>
 
 #include "absl/base/attributes.h"
+#include "absl/base/macros.h"
 #include "absl/meta/type_traits.h"
 
 namespace absl {
@@ -45,14 +46,23 @@
 using value_type = int8_t;
 
 class OnlyLiteralZero {
-  // A private type which cannot be named to explicitly cast to it.
-  struct MatchLiteralZero;
-
  public:
+#if ABSL_HAVE_ATTRIBUTE(enable_if)
+  // On clang, we can avoid triggering modernize-use-nullptr by only enabling
+  // this overload when the value is a compile time integer constant equal to 0.
+  //
+  // In c++20, this could be a static_assert in a consteval function.
+  constexpr OnlyLiteralZero(int n)  // NOLINT
+      __attribute__((enable_if(n == 0, "Only literal `0` is allowed."))) {}
+#else  // ABSL_HAVE_ATTRIBUTE(enable_if)
   // Accept only literal zero since it can be implicitly converted to a pointer
-  // type. nullptr constants will be caught by the other constructor which
-  // accepts a nullptr_t.
-  constexpr OnlyLiteralZero(MatchLiteralZero *) noexcept {}  // NOLINT
+  // to member type. nullptr constants will be caught by the other constructor
+  // which accepts a nullptr_t.
+  //
+  // This constructor is not used for clang since it triggers
+  // modernize-use-nullptr.
+  constexpr OnlyLiteralZero(int OnlyLiteralZero::*) noexcept {}  // NOLINT
+#endif
 
   // Fails compilation when `nullptr` or integral type arguments other than
   // `int` are passed. This constructor doesn't accept `int` because literal `0`