From 005a6c1f172f4508a9e00b413175750061174724 Mon Sep 17 00:00:00 2001
From: Marcelo Juchem <marcelo@fb.com>
Date: Sat, 30 Mar 2013 00:13:31 -0700
Subject: [PATCH] Fixing clang compatibility issues

Test Plan: all folly unit tests

Reviewed By: andrewjcg@fb.com

FB internal diff: D757374
---
 folly/Conv.h       | 12 ++++---
 folly/Format-inl.h |  6 ++--
 folly/Traits.h     | 87 ++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 97 insertions(+), 8 deletions(-)

diff --git a/folly/Conv.h b/folly/Conv.h
index 4ccacf22..c8360a6d 100644
--- a/folly/Conv.h
+++ b/folly/Conv.h
@@ -64,13 +64,17 @@ typename std::enable_if<
 to(const Src & value) {
   /* static */ if (std::numeric_limits<Tgt>::max()
                    < std::numeric_limits<Src>::max()) {
-    FOLLY_RANGE_CHECK(value <= std::numeric_limits<Tgt>::max(),
-                      "Overflow");
+    FOLLY_RANGE_CHECK(
+      (!greater_than<Tgt, std::numeric_limits<Tgt>::max()>(value)),
+      "Overflow"
+    );
   }
   /* static */ if (std::is_signed<Src>::value &&
                    (!std::is_signed<Tgt>::value || sizeof(Src) > sizeof(Tgt))) {
-    FOLLY_RANGE_CHECK(value >= std::numeric_limits<Tgt>::min(),
-                      "Negative overflow");
+    FOLLY_RANGE_CHECK(
+      (!less_than<Tgt, std::numeric_limits<Tgt>::min()>(value)),
+      "Negative overflow"
+    );
   }
   return static_cast<Tgt>(value);
 }
diff --git a/folly/Format-inl.h b/folly/Format-inl.h
index c8c90418..70672d47 100644
--- a/folly/Format-inl.h
+++ b/folly/Format-inl.h
@@ -18,6 +18,8 @@
 #error This file may only be included from Format.h.
 #endif
 
+#include "folly/Traits.h"
+
 namespace folly {
 
 namespace detail {
@@ -45,7 +47,7 @@ size_t uintToHex(char* buffer, size_t bufLen, Uint v,
                  const char (&repr)[256][2]) {
   // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
   // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
-  for (; v >= 256; v >>= 7, v >>= 1) {
+  for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
     auto b = v & 0xff;
     bufLen -= 2;
     buffer[bufLen] = repr[b][0];
@@ -89,7 +91,7 @@ size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
   auto& repr = formatOctal;
   // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
   // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
-  for (; v >= 512; v >>= 7, v >>= 2) {
+  for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
     auto b = v & 0x1ff;
     bufLen -= 3;
     buffer[bufLen] = repr[b][0];
diff --git a/folly/Traits.h b/folly/Traits.h
index ebdb84d1..db8bd33a 100644
--- a/folly/Traits.h
+++ b/folly/Traits.h
@@ -20,6 +20,7 @@
 #define FOLLY_BASE_TRAITS_H_
 
 #include <memory>
+#include <limits>
 #include <type_traits>
 
 #include <bits/c++config.h>
@@ -306,9 +307,13 @@ public:
 };
 
 /*
- * Complementary type traits to check for a negative/non-positive value.
+ * Complementary type traits for integral comparisons.
  *
- * `if(x < 0)` yields an error in clang for unsigned types when -Werror is used
+ * For instance, `if(x < 0)` yields an error in clang for unsigned types
+ *  when -Werror is used due to -Wtautological-compare
+ *
+ *
+ * @author: Marcelo Juchem <marcelo@fb.com>
  */
 
 namespace detail {
@@ -323,6 +328,68 @@ struct is_negative_impl<T, false> {
   constexpr static bool check(T x) { return false; }
 };
 
+template <typename RHS, RHS rhs, typename LHS>
+bool less_than_impl(
+  typename std::enable_if<
+    (rhs <= std::numeric_limits<LHS>::max()
+      && rhs >= std::numeric_limits<LHS>::min()),
+    LHS
+  >::type const lhs
+) {
+  return lhs < rhs;
+}
+
+template <typename RHS, RHS rhs, typename LHS>
+bool less_than_impl(
+  typename std::enable_if<
+    (rhs > std::numeric_limits<LHS>::max()),
+    LHS
+  >::type const
+) {
+  return true;
+}
+
+template <typename RHS, RHS rhs, typename LHS>
+bool less_than_impl(
+  typename std::enable_if<
+    (rhs < std::numeric_limits<LHS>::min()),
+    LHS
+  >::type const
+) {
+  return false;
+}
+
+template <typename LHS, LHS lhs, typename RHS>
+bool greater_than_impl(
+  typename std::enable_if<
+    (lhs <= std::numeric_limits<RHS>::max()
+      && lhs >= std::numeric_limits<RHS>::min()),
+    RHS
+  >::type const rhs
+) {
+  return lhs < rhs;
+}
+
+template <typename LHS, LHS lhs, typename RHS>
+bool greater_than_impl(
+  typename std::enable_if<
+    (lhs > std::numeric_limits<RHS>::max()),
+    RHS
+  >::type const
+) {
+  return false;
+}
+
+template <typename LHS, LHS lhs, typename RHS>
+bool greater_than_impl(
+  typename std::enable_if<
+    (lhs < std::numeric_limits<RHS>::min()),
+    RHS
+  >::type const
+) {
+  return true;
+}
+
 } // namespace detail {
 
 // same as `x < 0`
@@ -335,6 +402,20 @@ constexpr bool is_negative(T x) {
 template <typename T>
 constexpr bool is_non_positive(T x) { return !x || folly::is_negative(x); }
 
+template <typename RHS, RHS rhs, typename LHS>
+bool less_than(LHS const lhs) {
+  return detail::less_than_impl<
+    RHS, rhs, typename std::remove_reference<LHS>::type
+  >(lhs);
+}
+
+template <typename LHS, LHS lhs, typename RHS>
+bool greater_than(RHS const rhs) {
+  return detail::greater_than_impl<
+    LHS, lhs, typename std::remove_reference<RHS>::type
+  >(rhs);
+}
+
 } // namespace folly
 
 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(std::basic_string);
@@ -410,6 +491,8 @@ FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(boost::shared_ptr);
  *   cout << "Does class Bar have a member double test(const string&, long)? "
  *     << boolalpha << has_test_traits<Bar, double(const string&, long)>::value;
  * }
+ *
+ * @author: Marcelo Juchem <marcelo@fb.com>
  */
 #define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(classname, func_name) \
   template <typename, typename> class classname; \
-- 
2.34.1