Skip to content

Commit

Permalink
Fix the implementation of OnlyLiteralZero (#1420)
Browse files Browse the repository at this point in the history
This patch changes the implementation of OnlyLiteralZero to only fail if the second overload is chosen, instead of failing during overload resolution.

This patch cherry-picks 2de126c.

Fixes #1419
  • Loading branch information
derekmauro authored Mar 27, 2023
1 parent c8a2f92 commit b971ac5
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 61 deletions.
2 changes: 1 addition & 1 deletion absl/base/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
// LTS releases can be obtained from
// https://github.com/abseil/abseil-cpp/releases.
#define ABSL_LTS_RELEASE_VERSION 20230125
#define ABSL_LTS_RELEASE_PATCH_LEVEL 1
#define ABSL_LTS_RELEASE_PATCH_LEVEL 2

// Helper macro to convert a CPP variable to a string literal.
#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x
Expand Down
119 changes: 59 additions & 60 deletions absl/types/compare.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,29 +44,28 @@ namespace compare_internal {

using value_type = int8_t;

template <typename T>
struct Fail {
static_assert(sizeof(T) < 0, "Only literal `0` is allowed.");
};
class OnlyLiteralZero {
// A private type which cannot be named to explicitly cast to it.
struct MatchLiteralZero;

// We need the NullPtrT template to avoid triggering the modernize-use-nullptr
// ClangTidy warning in user code.
template <typename NullPtrT = std::nullptr_t>
struct OnlyLiteralZero {
constexpr OnlyLiteralZero(NullPtrT) noexcept {} // NOLINT
public:
// 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

// Fails compilation when `nullptr` or integral type arguments other than
// `int` are passed. This constructor doesn't accept `int` because literal `0`
// has type `int`. Literal `0` arguments will be implicitly converted to
// `std::nullptr_t` and accepted by the above constructor, while other `int`
// arguments will fail to be converted and cause compilation failure.
template <
typename T,
typename = typename std::enable_if<
std::is_same<T, std::nullptr_t>::value ||
(std::is_integral<T>::value && !std::is_same<T, int>::value)>::type,
typename = typename Fail<T>::type>
OnlyLiteralZero(T); // NOLINT
template <typename T, typename = typename std::enable_if<
std::is_same<T, std::nullptr_t>::value ||
(std::is_integral<T>::value &&
!std::is_same<T, int>::value)>::type>
OnlyLiteralZero(T) { // NOLINT
static_assert(sizeof(T) < 0, "Only literal `0` is allowed.");
}
};

enum class eq : value_type {
Expand Down Expand Up @@ -163,18 +162,18 @@ class weak_equality

// Comparisons
friend constexpr bool operator==(
weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
weak_equality v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ == 0;
}
friend constexpr bool operator!=(
weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
weak_equality v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ != 0;
}
friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
weak_equality v) noexcept {
return 0 == v.value_;
}
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero,
weak_equality v) noexcept {
return 0 != v.value_;
}
Expand Down Expand Up @@ -214,18 +213,18 @@ class strong_equality
}
// Comparisons
friend constexpr bool operator==(
strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
strong_equality v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ == 0;
}
friend constexpr bool operator!=(
strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
strong_equality v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ != 0;
}
friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
strong_equality v) noexcept {
return 0 == v.value_;
}
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero,
strong_equality v) noexcept {
return 0 != v.value_;
}
Expand Down Expand Up @@ -277,50 +276,50 @@ class partial_ordering
}
// Comparisons
friend constexpr bool operator==(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.is_ordered() && v.value_ == 0;
}
friend constexpr bool operator!=(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return !v.is_ordered() || v.value_ != 0;
}
friend constexpr bool operator<(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.is_ordered() && v.value_ < 0;
}
friend constexpr bool operator<=(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.is_ordered() && v.value_ <= 0;
}
friend constexpr bool operator>(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.is_ordered() && v.value_ > 0;
}
friend constexpr bool operator>=(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.is_ordered() && v.value_ >= 0;
}
friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
partial_ordering v) noexcept {
return v.is_ordered() && 0 == v.value_;
}
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero,
partial_ordering v) noexcept {
return !v.is_ordered() || 0 != v.value_;
}
friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator<(compare_internal::OnlyLiteralZero,
partial_ordering v) noexcept {
return v.is_ordered() && 0 < v.value_;
}
friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator<=(compare_internal::OnlyLiteralZero,
partial_ordering v) noexcept {
return v.is_ordered() && 0 <= v.value_;
}
friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator>(compare_internal::OnlyLiteralZero,
partial_ordering v) noexcept {
return v.is_ordered() && 0 > v.value_;
}
friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator>=(compare_internal::OnlyLiteralZero,
partial_ordering v) noexcept {
return v.is_ordered() && 0 >= v.value_;
}
Expand Down Expand Up @@ -369,50 +368,50 @@ class weak_ordering
}
// Comparisons
friend constexpr bool operator==(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ == 0;
}
friend constexpr bool operator!=(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ != 0;
}
friend constexpr bool operator<(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ < 0;
}
friend constexpr bool operator<=(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ <= 0;
}
friend constexpr bool operator>(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ > 0;
}
friend constexpr bool operator>=(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ >= 0;
}
friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
weak_ordering v) noexcept {
return 0 == v.value_;
}
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero,
weak_ordering v) noexcept {
return 0 != v.value_;
}
friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator<(compare_internal::OnlyLiteralZero,
weak_ordering v) noexcept {
return 0 < v.value_;
}
friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator<=(compare_internal::OnlyLiteralZero,
weak_ordering v) noexcept {
return 0 <= v.value_;
}
friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator>(compare_internal::OnlyLiteralZero,
weak_ordering v) noexcept {
return 0 > v.value_;
}
friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator>=(compare_internal::OnlyLiteralZero,
weak_ordering v) noexcept {
return 0 >= v.value_;
}
Expand Down Expand Up @@ -468,50 +467,50 @@ class strong_ordering
}
// Comparisons
friend constexpr bool operator==(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ == 0;
}
friend constexpr bool operator!=(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ != 0;
}
friend constexpr bool operator<(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ < 0;
}
friend constexpr bool operator<=(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ <= 0;
}
friend constexpr bool operator>(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ > 0;
}
friend constexpr bool operator>=(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
return v.value_ >= 0;
}
friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
strong_ordering v) noexcept {
return 0 == v.value_;
}
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero,
strong_ordering v) noexcept {
return 0 != v.value_;
}
friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator<(compare_internal::OnlyLiteralZero,
strong_ordering v) noexcept {
return 0 < v.value_;
}
friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator<=(compare_internal::OnlyLiteralZero,
strong_ordering v) noexcept {
return 0 <= v.value_;
}
friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator>(compare_internal::OnlyLiteralZero,
strong_ordering v) noexcept {
return 0 > v.value_;
}
friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
friend constexpr bool operator>=(compare_internal::OnlyLiteralZero,
strong_ordering v) noexcept {
return 0 >= v.value_;
}
Expand Down

0 comments on commit b971ac5

Please sign in to comment.