Update third_party/base/numerics.

Sync with Chromium's copy at https://crrev.com/992474 to pick up changes
like https://crrev.com/957561 and https://crrev.com/958889.

Change-Id: Id8be1ca177c5cc369b6eaabae6b32e51b7bc23bc
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/93380
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/third_party/base/numerics/checked_math.h b/third_party/base/numerics/checked_math.h
index 2da3677..eb0d9a5 100644
--- a/third_party/base/numerics/checked_math.h
+++ b/third_party/base/numerics/checked_math.h
@@ -22,6 +22,9 @@
                 "CheckedNumeric<T>: T must be a numeric type.");
 
  public:
+  template <typename Src>
+  friend class CheckedNumeric;
+
   using type = T;
 
   constexpr CheckedNumeric() = default;
@@ -31,15 +34,12 @@
   constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs)
       : state_(rhs.state_.value(), rhs.IsValid()) {}
 
-  template <typename Src>
-  friend class CheckedNumeric;
-
   // This is not an explicit constructor because we implicitly upgrade regular
   // numerics to CheckedNumerics to make them easier to use.
   template <typename Src>
   constexpr CheckedNumeric(Src value)  // NOLINT(runtime/explicit)
       : state_(value) {
-    static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
+    static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric.");
   }
 
   // This is not an explicit constructor because we want a seamless conversion
@@ -111,7 +111,7 @@
   }
 
   // This friend method is available solely for providing more detailed logging
-  // in the the tests. Do not implement it in production code, because the
+  // in the tests. Do not implement it in production code, because the
   // underlying values may change at any time.
   template <typename U>
   friend U GetNumericValueForTest(const CheckedNumeric<U>& src);
@@ -139,18 +139,17 @@
   constexpr CheckedNumeric& operator^=(const Src rhs);
 
   constexpr CheckedNumeric operator-() const {
-    // The negation of two's complement int min is int min, so we simply
-    // check for that in the constexpr case.
-    // We use an optimized code path for a known run-time variable.
-    return MustTreatAsConstexpr(state_.value()) || !std::is_signed<T>::value ||
-                   std::is_floating_point<T>::value
-               ? CheckedNumeric<T>(
-                     NegateWrapper(state_.value()),
-                     IsValid() && (!std::is_signed<T>::value ||
-                                   std::is_floating_point<T>::value ||
-                                   NegateWrapper(state_.value()) !=
-                                       std::numeric_limits<T>::lowest()))
-               : FastRuntimeNegate();
+    // Use an optimized code path for a known run-time variable.
+    if (!IsConstantEvaluated() && std::is_signed<T>::value &&
+        std::is_floating_point<T>::value) {
+      return FastRuntimeNegate();
+    }
+    // The negation of two's complement int min is int min.
+    const bool is_valid =
+        IsValid() &&
+        (!std::is_signed<T>::value || std::is_floating_point<T>::value ||
+         NegateWrapper(state_.value()) != std::numeric_limits<T>::lowest());
+    return CheckedNumeric<T>(NegateWrapper(state_.value()), is_valid);
   }
 
   constexpr CheckedNumeric operator~() const {
@@ -165,31 +164,13 @@
   template <typename U>
   constexpr CheckedNumeric<typename MathWrapper<CheckedMaxOp, T, U>::type> Max(
       const U rhs) const {
-    using R = typename UnderlyingType<U>::type;
-    using result_type = typename MathWrapper<CheckedMaxOp, T, U>::type;
-    // TODO(jschuh): This can be converted to the MathOp version and remain
-    // constexpr once we have C++14 support.
-    return CheckedNumeric<result_type>(
-        static_cast<result_type>(
-            IsGreater<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
-                ? state_.value()
-                : Wrapper<U>::value(rhs)),
-        state_.is_valid() && Wrapper<U>::is_valid(rhs));
+    return CheckMax(*this, rhs);
   }
 
   template <typename U>
   constexpr CheckedNumeric<typename MathWrapper<CheckedMinOp, T, U>::type> Min(
       const U rhs) const {
-    using R = typename UnderlyingType<U>::type;
-    using result_type = typename MathWrapper<CheckedMinOp, T, U>::type;
-    // TODO(jschuh): This can be converted to the MathOp version and remain
-    // constexpr once we have C++14 support.
-    return CheckedNumeric<result_type>(
-        static_cast<result_type>(
-            IsLess<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
-                ? state_.value()
-                : Wrapper<U>::value(rhs)),
-        state_.is_valid() && Wrapper<U>::is_valid(rhs));
+    return CheckMin(*this, rhs);
   }
 
   // This function is available only for integral types. It returns an unsigned
@@ -218,7 +199,8 @@
   }
 
   constexpr CheckedNumeric operator--(int) {
-    CheckedNumeric value = *this;
+    // TODO(pkasting): Consider std::exchange() once it's constexpr in C++20.
+    const CheckedNumeric value = *this;
     *this -= 1;
     return value;
   }
@@ -231,7 +213,7 @@
   static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) {
     using Math = typename MathWrapper<M, L, R>::math;
     T result = 0;
-    bool is_valid =
+    const bool is_valid =
         Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) &&
         Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result);
     return CheckedNumeric<T>(result, is_valid);
@@ -242,8 +224,9 @@
   constexpr CheckedNumeric& MathOp(const R rhs) {
     using Math = typename MathWrapper<M, T, R>::math;
     T result = 0;  // Using T as the destination saves a range check.
-    bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
-                    Math::Do(state_.value(), Wrapper<R>::value(rhs), &result);
+    const bool is_valid =
+        state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
+        Math::Do(state_.value(), Wrapper<R>::value(rhs), &result);
     *this = CheckedNumeric<T>(result, is_valid);
     return *this;
   }
@@ -253,7 +236,7 @@
 
   CheckedNumeric FastRuntimeNegate() const {
     T result;
-    bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result);
+    const bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result);
     return CheckedNumeric<T>(result, IsValid() && success);
   }
 
@@ -307,8 +290,8 @@
   return value.template ValueOrDefault<Dst>(default_value);
 }
 
-// Convience wrapper to return a new CheckedNumeric from the provided arithmetic
-// or CheckedNumericType.
+// Convenience wrapper to return a new CheckedNumeric from the provided
+// arithmetic or CheckedNumericType.
 template <typename T>
 constexpr CheckedNumeric<typename UnderlyingType<T>::type> MakeCheckedNum(
     const T value) {
@@ -332,8 +315,7 @@
           typename L,
           typename R,
           typename... Args>
-constexpr CheckedNumeric<typename ResultType<M, L, R, Args...>::type>
-CheckMathOp(const L lhs, const R rhs, const Args... args) {
+constexpr auto CheckMathOp(const L lhs, const R rhs, const Args... args) {
   return CheckMathOp<M>(CheckMathOp<M>(lhs, rhs), args...);
 }
 
@@ -355,39 +337,39 @@
 // bad, we trigger the CHECK condition here.
 template <typename L, typename R>
 L* operator+(L* lhs, const StrictNumeric<R> rhs) {
-  uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
-                              CheckMul(sizeof(L), static_cast<R>(rhs)))
-                         .template ValueOrDie<uintptr_t>();
+  const uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
+                                    CheckMul(sizeof(L), static_cast<R>(rhs)))
+                               .template ValueOrDie<uintptr_t>();
   return reinterpret_cast<L*>(result);
 }
 
 template <typename L, typename R>
 L* operator-(L* lhs, const StrictNumeric<R> rhs) {
-  uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
-                              CheckMul(sizeof(L), static_cast<R>(rhs)))
-                         .template ValueOrDie<uintptr_t>();
+  const uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
+                                    CheckMul(sizeof(L), static_cast<R>(rhs)))
+                               .template ValueOrDie<uintptr_t>();
   return reinterpret_cast<L*>(result);
 }
 
 }  // namespace internal
 
+using internal::CheckAdd;
+using internal::CheckAnd;
+using internal::CheckDiv;
 using internal::CheckedNumeric;
-using internal::IsValidForType;
-using internal::ValueOrDieForType;
-using internal::ValueOrDefaultForType;
-using internal::MakeCheckedNum;
+using internal::CheckLsh;
 using internal::CheckMax;
 using internal::CheckMin;
-using internal::CheckAdd;
-using internal::CheckSub;
-using internal::CheckMul;
-using internal::CheckDiv;
 using internal::CheckMod;
-using internal::CheckLsh;
-using internal::CheckRsh;
-using internal::CheckAnd;
+using internal::CheckMul;
 using internal::CheckOr;
+using internal::CheckRsh;
+using internal::CheckSub;
 using internal::CheckXor;
+using internal::IsValidForType;
+using internal::MakeCheckedNum;
+using internal::ValueOrDefaultForType;
+using internal::ValueOrDieForType;
 
 }  // namespace base
 }  // namespace pdfium
diff --git a/third_party/base/numerics/checked_math_impl.h b/third_party/base/numerics/checked_math_impl.h
index 3227817..e61053d 100644
--- a/third_party/base/numerics/checked_math_impl.h
+++ b/third_party/base/numerics/checked_math_impl.h
@@ -28,15 +28,17 @@
   // it using the unsigned type of the same size.
   using UnsignedDst = typename std::make_unsigned<T>::type;
   using SignedDst = typename std::make_signed<T>::type;
-  UnsignedDst ux = static_cast<UnsignedDst>(x);
-  UnsignedDst uy = static_cast<UnsignedDst>(y);
-  UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
-  *result = static_cast<T>(uresult);
+  const UnsignedDst ux = static_cast<UnsignedDst>(x);
+  const UnsignedDst uy = static_cast<UnsignedDst>(y);
+  const UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
   // Addition is valid if the sign of (x + y) is equal to either that of x or
   // that of y.
-  return (std::is_signed<T>::value)
-             ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) >= 0
-             : uresult >= uy;  // Unsigned is either valid or underflow.
+  if (std::is_signed<T>::value
+          ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) < 0
+          : uresult < uy)  // Unsigned is either valid or underflow.
+    return false;
+  *result = static_cast<T>(uresult);
+  return true;
 }
 
 template <typename T, typename U, class Enable = void>
@@ -50,8 +52,7 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V>
   static constexpr bool Do(T x, U y, V* result) {
-    // TODO(jschuh) Make this "constexpr if" once we're C++17.
-    if (CheckedAddFastOp<T, U>::is_supported)
+    if constexpr (CheckedAddFastOp<T, U>::is_supported)
       return CheckedAddFastOp<T, U>::Do(x, y, result);
 
     // Double the underlying type up to a full machine word.
@@ -76,8 +77,10 @@
       is_valid = CheckedAddImpl(static_cast<Promotion>(x),
                                 static_cast<Promotion>(y), &presult);
     }
+    if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
+      return false;
     *result = static_cast<V>(presult);
-    return is_valid && IsValueInRangeForNumericType<V>(presult);
+    return true;
   }
 };
 
@@ -88,15 +91,17 @@
   // it using the unsigned type of the same size.
   using UnsignedDst = typename std::make_unsigned<T>::type;
   using SignedDst = typename std::make_signed<T>::type;
-  UnsignedDst ux = static_cast<UnsignedDst>(x);
-  UnsignedDst uy = static_cast<UnsignedDst>(y);
-  UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
-  *result = static_cast<T>(uresult);
+  const UnsignedDst ux = static_cast<UnsignedDst>(x);
+  const UnsignedDst uy = static_cast<UnsignedDst>(y);
+  const UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
   // Subtraction is valid if either x and y have same sign, or (x-y) and x have
   // the same sign.
-  return (std::is_signed<T>::value)
-             ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) >= 0
-             : x >= y;
+  if (std::is_signed<T>::value
+          ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) < 0
+          : x < y)
+    return false;
+  *result = static_cast<T>(uresult);
+  return true;
 }
 
 template <typename T, typename U, class Enable = void>
@@ -110,8 +115,7 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V>
   static constexpr bool Do(T x, U y, V* result) {
-    // TODO(jschuh) Make this "constexpr if" once we're C++17.
-    if (CheckedSubFastOp<T, U>::is_supported)
+    if constexpr (CheckedSubFastOp<T, U>::is_supported)
       return CheckedSubFastOp<T, U>::Do(x, y, result);
 
     // Double the underlying type up to a full machine word.
@@ -136,8 +140,10 @@
       is_valid = CheckedSubImpl(static_cast<Promotion>(x),
                                 static_cast<Promotion>(y), &presult);
     }
+    if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
+      return false;
     *result = static_cast<V>(presult);
-    return is_valid && IsValueInRangeForNumericType<V>(presult);
+    return true;
   }
 };
 
@@ -150,15 +156,17 @@
   using SignedDst = typename std::make_signed<T>::type;
   const UnsignedDst ux = SafeUnsignedAbs(x);
   const UnsignedDst uy = SafeUnsignedAbs(y);
-  UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
+  const UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
   const bool is_negative =
       std::is_signed<T>::value && static_cast<SignedDst>(x ^ y) < 0;
-  *result = is_negative ? 0 - uresult : uresult;
   // We have a fast out for unsigned identity or zero on the second operand.
   // After that it's an unsigned overflow check on the absolute value, with
   // a +1 bound for a negative result.
-  return uy <= UnsignedDst(!std::is_signed<T>::value || is_negative) ||
-         ux <= (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy;
+  if (uy > UnsignedDst(!std::is_signed<T>::value || is_negative) &&
+      ux > (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy)
+    return false;
+  *result = is_negative ? 0 - uresult : uresult;
+  return true;
 }
 
 template <typename T, typename U, class Enable = void>
@@ -172,8 +180,7 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V>
   static constexpr bool Do(T x, U y, V* result) {
-    // TODO(jschuh) Make this "constexpr if" once we're C++17.
-    if (CheckedMulFastOp<T, U>::is_supported)
+    if constexpr (CheckedMulFastOp<T, U>::is_supported)
       return CheckedMulFastOp<T, U>::Do(x, y, result);
 
     using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
@@ -195,8 +202,10 @@
       is_valid = CheckedMulImpl(static_cast<Promotion>(x),
                                 static_cast<Promotion>(y), &presult);
     }
+    if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
+      return false;
     *result = static_cast<V>(presult);
-    return is_valid && IsValueInRangeForNumericType<V>(presult);
+    return true;
   }
 };
 
@@ -235,9 +244,11 @@
       return false;
     }
 
-    Promotion presult = Promotion(x) / Promotion(y);
+    const Promotion presult = Promotion(x) / Promotion(y);
+    if (!IsValueInRangeForNumericType<V>(presult))
+      return false;
     *result = static_cast<V>(presult);
-    return IsValueInRangeForNumericType<V>(presult);
+    return true;
   }
 };
 
@@ -266,9 +277,12 @@
       return true;
     }
 
-    Promotion presult = static_cast<Promotion>(x) % static_cast<Promotion>(y);
+    const Promotion presult =
+        static_cast<Promotion>(x) % static_cast<Promotion>(y);
+    if (!IsValueInRangeForNumericType<V>(presult))
+      return false;
     *result = static_cast<Promotion>(presult);
-    return IsValueInRangeForNumericType<V>(presult);
+    return true;
   }
 };
 
@@ -297,8 +311,11 @@
     }
 
     // Handle the legal corner-case of a full-width signed shift of zero.
-    return std::is_signed<T>::value && !x &&
-           as_unsigned(shift) == as_unsigned(std::numeric_limits<T>::digits);
+    if (!std::is_signed<T>::value || x ||
+        as_unsigned(shift) != as_unsigned(std::numeric_limits<T>::digits))
+      return false;
+    *result = 0;
+    return true;
   }
 };
 
@@ -315,15 +332,18 @@
                                             std::is_integral<U>::value>::type> {
   using result_type = T;
   template <typename V>
-  static bool Do(T x, U shift, V* result) {
-    // Use the type conversion push negative values out of range.
-    if (BASE_NUMERICS_LIKELY(as_unsigned(shift) <
-                             IntegerBitsPlusSign<T>::value)) {
-      T tmp = x >> shift;
-      *result = static_cast<V>(tmp);
-      return IsValueInRangeForNumericType<V>(tmp);
+  static constexpr bool Do(T x, U shift, V* result) {
+    // Use sign conversion to push negative values out of range.
+    if (BASE_NUMERICS_UNLIKELY(as_unsigned(shift) >=
+                               IntegerBitsPlusSign<T>::value)) {
+      return false;
     }
-    return false;
+
+    const T tmp = x >> shift;
+    if (!IsValueInRangeForNumericType<V>(tmp))
+      return false;
+    *result = static_cast<V>(tmp);
+    return true;
   }
 };
 
@@ -340,9 +360,12 @@
       typename MaxExponentPromotion<T, U>::type>::type;
   template <typename V>
   static constexpr bool Do(T x, U y, V* result) {
-    result_type tmp = static_cast<result_type>(x) & static_cast<result_type>(y);
+    const result_type tmp =
+        static_cast<result_type>(x) & static_cast<result_type>(y);
+    if (!IsValueInRangeForNumericType<V>(tmp))
+      return false;
     *result = static_cast<V>(tmp);
-    return IsValueInRangeForNumericType<V>(tmp);
+    return true;
   }
 };
 
@@ -359,9 +382,12 @@
       typename MaxExponentPromotion<T, U>::type>::type;
   template <typename V>
   static constexpr bool Do(T x, U y, V* result) {
-    result_type tmp = static_cast<result_type>(x) | static_cast<result_type>(y);
+    const result_type tmp =
+        static_cast<result_type>(x) | static_cast<result_type>(y);
+    if (!IsValueInRangeForNumericType<V>(tmp))
+      return false;
     *result = static_cast<V>(tmp);
-    return IsValueInRangeForNumericType<V>(tmp);
+    return true;
   }
 };
 
@@ -378,9 +404,12 @@
       typename MaxExponentPromotion<T, U>::type>::type;
   template <typename V>
   static constexpr bool Do(T x, U y, V* result) {
-    result_type tmp = static_cast<result_type>(x) ^ static_cast<result_type>(y);
+    const result_type tmp =
+        static_cast<result_type>(x) ^ static_cast<result_type>(y);
+    if (!IsValueInRangeForNumericType<V>(tmp))
+      return false;
     *result = static_cast<V>(tmp);
-    return IsValueInRangeForNumericType<V>(tmp);
+    return true;
   }
 };
 
@@ -398,10 +427,13 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V>
   static constexpr bool Do(T x, U y, V* result) {
-    result_type tmp = IsGreater<T, U>::Test(x, y) ? static_cast<result_type>(x)
-                                                  : static_cast<result_type>(y);
+    const result_type tmp = IsGreater<T, U>::Test(x, y)
+                                ? static_cast<result_type>(x)
+                                : static_cast<result_type>(y);
+    if (!IsValueInRangeForNumericType<V>(tmp))
+      return false;
     *result = static_cast<V>(tmp);
-    return IsValueInRangeForNumericType<V>(tmp);
+    return true;
   }
 };
 
@@ -419,10 +451,13 @@
   using result_type = typename LowestValuePromotion<T, U>::type;
   template <typename V>
   static constexpr bool Do(T x, U y, V* result) {
-    result_type tmp = IsLess<T, U>::Test(x, y) ? static_cast<result_type>(x)
-                                               : static_cast<result_type>(y);
+    const result_type tmp = IsLess<T, U>::Test(x, y)
+                                ? static_cast<result_type>(x)
+                                : static_cast<result_type>(y);
+    if (!IsValueInRangeForNumericType<V>(tmp))
+      return false;
     *result = static_cast<V>(tmp);
-    return IsValueInRangeForNumericType<V>(tmp);
+    return true;
   }
 };
 
@@ -438,9 +473,11 @@
     template <typename V>                                                \
     static constexpr bool Do(T x, U y, V* result) {                      \
       using Promotion = typename MaxExponentPromotion<T, U>::type;       \
-      Promotion presult = x OP y;                                        \
+      const Promotion presult = x OP y;                                  \
+      if (!IsValueInRangeForNumericType<V>(presult))                     \
+        return false;                                                    \
       *result = static_cast<V>(presult);                                 \
-      return IsValueInRangeForNumericType<V>(presult);                   \
+      return true;                                                       \
     }                                                                    \
   };
 
@@ -476,61 +513,67 @@
 // Integrals require quite a bit of additional housekeeping to manage state.
 template <typename T>
 class CheckedNumericState<T, NUMERIC_INTEGER> {
- private:
-  // is_valid_ precedes value_ because member intializers in the constructors
-  // are evaluated in field order, and is_valid_ must be read when initializing
-  // value_.
-  bool is_valid_;
-  T value_;
-
-  // Ensures that a type conversion does not trigger undefined behavior.
-  template <typename Src>
-  static constexpr T WellDefinedConversionOrZero(const Src value,
-                                                 const bool is_valid) {
-    using SrcType = typename internal::UnderlyingType<Src>::type;
-    return (std::is_integral<SrcType>::value || is_valid)
-               ? static_cast<T>(value)
-               : static_cast<T>(0);
-  }
-
  public:
-  template <typename Src, NumericRepresentation type>
-  friend class CheckedNumericState;
-
-  constexpr CheckedNumericState() : is_valid_(true), value_(0) {}
-
-  template <typename Src>
-  constexpr CheckedNumericState(Src value, bool is_valid)
+  template <typename Src = int>
+  constexpr explicit CheckedNumericState(Src value = 0, bool is_valid = true)
       : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
         value_(WellDefinedConversionOrZero(value, is_valid_)) {
     static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
   }
 
-  // Copy constructor.
   template <typename Src>
   constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
-      : is_valid_(rhs.IsValid()),
-        value_(WellDefinedConversionOrZero(rhs.value(), is_valid_)) {}
-
-  template <typename Src>
-  constexpr explicit CheckedNumericState(Src value)
-      : is_valid_(IsValueInRangeForNumericType<T>(value)),
-        value_(WellDefinedConversionOrZero(value, is_valid_)) {}
+      : CheckedNumericState(rhs.value(), rhs.is_valid()) {}
 
   constexpr bool is_valid() const { return is_valid_; }
+
   constexpr T value() const { return value_; }
+
+ private:
+  // Ensures that a type conversion does not trigger undefined behavior.
+  template <typename Src>
+  static constexpr T WellDefinedConversionOrZero(Src value, bool is_valid) {
+    using SrcType = typename internal::UnderlyingType<Src>::type;
+    return (std::is_integral<SrcType>::value || is_valid)
+               ? static_cast<T>(value)
+               : 0;
+  }
+
+  // is_valid_ precedes value_ because member initializers in the constructors
+  // are evaluated in field order, and is_valid_ must be read when initializing
+  // value_.
+  bool is_valid_;
+  T value_;
 };
 
 // Floating points maintain their own validity, but need translation wrappers.
 template <typename T>
 class CheckedNumericState<T, NUMERIC_FLOATING> {
- private:
-  T value_;
+ public:
+  template <typename Src = double>
+  constexpr explicit CheckedNumericState(Src value = 0.0, bool is_valid = true)
+      : value_(WellDefinedConversionOrNaN(
+            value,
+            is_valid && IsValueInRangeForNumericType<T>(value))) {}
 
+  template <typename Src>
+  constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
+      : CheckedNumericState(rhs.value(), rhs.is_valid()) {}
+
+  constexpr bool is_valid() const {
+    // Written this way because std::isfinite is not reliably constexpr.
+    return IsConstantEvaluated()
+               ? value_ <= std::numeric_limits<T>::max() &&
+                     value_ >= std::numeric_limits<T>::lowest()
+               : std::isfinite(value_);
+  }
+
+  constexpr T value() const { return value_; }
+
+ private:
   // Ensures that a type conversion does not trigger undefined behavior.
   template <typename Src>
-  static constexpr T WellDefinedConversionOrNaN(const Src value,
-                                                const bool is_valid) {
+  static constexpr T WellDefinedConversionOrNaN(Src value, bool is_valid) {
     using SrcType = typename internal::UnderlyingType<Src>::type;
     return (StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
                 NUMERIC_RANGE_CONTAINED ||
@@ -539,37 +582,7 @@
                : std::numeric_limits<T>::quiet_NaN();
   }
 
- public:
-  template <typename Src, NumericRepresentation type>
-  friend class CheckedNumericState;
-
-  constexpr CheckedNumericState() : value_(0.0) {}
-
-  template <typename Src>
-  constexpr CheckedNumericState(Src value, bool is_valid)
-      : value_(WellDefinedConversionOrNaN(value, is_valid)) {}
-
-  template <typename Src>
-  constexpr explicit CheckedNumericState(Src value)
-      : value_(WellDefinedConversionOrNaN(
-            value,
-            IsValueInRangeForNumericType<T>(value))) {}
-
-  // Copy constructor.
-  template <typename Src>
-  constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
-      : value_(WellDefinedConversionOrNaN(
-            rhs.value(),
-            rhs.is_valid() && IsValueInRangeForNumericType<T>(rhs.value()))) {}
-
-  constexpr bool is_valid() const {
-    // Written this way because std::isfinite is not reliably constexpr.
-    return MustTreatAsConstexpr(value_)
-               ? value_ <= std::numeric_limits<T>::max() &&
-                     value_ >= std::numeric_limits<T>::lowest()
-               : std::isfinite(value_);
-  }
-  constexpr T value() const { return value_; }
+  T value_;
 };
 
 }  // namespace internal
diff --git a/third_party/base/numerics/clamped_math.h b/third_party/base/numerics/clamped_math.h
index c2f25c5..ffa48f0 100644
--- a/third_party/base/numerics/clamped_math.h
+++ b/third_party/base/numerics/clamped_math.h
@@ -39,7 +39,7 @@
   template <typename Src>
   constexpr ClampedNumeric(Src value)  // NOLINT(runtime/explicit)
       : value_(saturated_cast<T>(value)) {
-    static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
+    static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric.");
   }
 
   // This is not an explicit constructor because we want a seamless conversion
@@ -179,14 +179,14 @@
   // ClampedNumeric and POD arithmetic types.
   template <typename Src>
   struct Wrapper {
-    static constexpr Src value(Src value) {
-      return static_cast<typename UnderlyingType<Src>::type>(value);
+    static constexpr typename UnderlyingType<Src>::type value(Src value) {
+      return value;
     }
   };
 };
 
-// Convience wrapper to return a new ClampedNumeric from the provided arithmetic
-// or ClampedNumericType.
+// Convenience wrapper to return a new ClampedNumeric from the provided
+// arithmetic or ClampedNumericType.
 template <typename T>
 constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum(
     const T value) {
@@ -210,8 +210,7 @@
           typename L,
           typename R,
           typename... Args>
-constexpr ClampedNumeric<typename ResultType<M, L, R, Args...>::type>
-ClampMathOp(const L lhs, const R rhs, const Args... args) {
+constexpr auto ClampMathOp(const L lhs, const R rhs, const Args... args) {
   return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...);
 }
 
@@ -236,20 +235,20 @@
 
 }  // namespace internal
 
+using internal::ClampAdd;
+using internal::ClampAnd;
+using internal::ClampDiv;
 using internal::ClampedNumeric;
-using internal::MakeClampedNum;
+using internal::ClampLsh;
 using internal::ClampMax;
 using internal::ClampMin;
-using internal::ClampAdd;
-using internal::ClampSub;
-using internal::ClampMul;
-using internal::ClampDiv;
 using internal::ClampMod;
-using internal::ClampLsh;
-using internal::ClampRsh;
-using internal::ClampAnd;
+using internal::ClampMul;
 using internal::ClampOr;
+using internal::ClampRsh;
+using internal::ClampSub;
 using internal::ClampXor;
+using internal::MakeClampedNum;
 
 }  // namespace base
 }  // namespace pdfium
diff --git a/third_party/base/numerics/clamped_math_impl.h b/third_party/base/numerics/clamped_math_impl.h
index 9922051..10b097f 100644
--- a/third_party/base/numerics/clamped_math_impl.h
+++ b/third_party/base/numerics/clamped_math_impl.h
@@ -26,7 +26,7 @@
           typename std::enable_if<std::is_integral<T>::value &&
                                   std::is_signed<T>::value>::type* = nullptr>
 constexpr T SaturatedNegWrapper(T value) {
-  return MustTreatAsConstexpr(value) || !ClampedNegFastOp<T>::is_supported
+  return IsConstantEvaluated() || !ClampedNegFastOp<T>::is_supported
              ? (NegateWrapper(value) != std::numeric_limits<T>::lowest()
                     ? NegateWrapper(value)
                     : std::numeric_limits<T>::max())
@@ -80,7 +80,7 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V = result_type>
   static constexpr V Do(T x, U y) {
-    if (ClampedAddFastOp<T, U>::is_supported)
+    if (!IsConstantEvaluated() && ClampedAddFastOp<T, U>::is_supported)
       return ClampedAddFastOp<T, U>::template Do<V>(x, y);
 
     static_assert(std::is_same<V, result_type>::value ||
@@ -106,8 +106,7 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V = result_type>
   static constexpr V Do(T x, U y) {
-    // TODO(jschuh) Make this "constexpr if" once we're C++17.
-    if (ClampedSubFastOp<T, U>::is_supported)
+    if (!IsConstantEvaluated() && ClampedSubFastOp<T, U>::is_supported)
       return ClampedSubFastOp<T, U>::template Do<V>(x, y);
 
     static_assert(std::is_same<V, result_type>::value ||
@@ -133,8 +132,7 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V = result_type>
   static constexpr V Do(T x, U y) {
-    // TODO(jschuh) Make this "constexpr if" once we're C++17.
-    if (ClampedMulFastOp<T, U>::is_supported)
+    if (!IsConstantEvaluated() && ClampedMulFastOp<T, U>::is_supported)
       return ClampedMulFastOp<T, U>::template Do<V>(x, y);
 
     V result = {};
diff --git a/third_party/base/numerics/safe_conversions.h b/third_party/base/numerics/safe_conversions.h
index 244f16c..bcc7ba8 100644
--- a/third_party/base/numerics/safe_conversions.h
+++ b/third_party/base/numerics/safe_conversions.h
@@ -7,18 +7,23 @@
 
 #include <stddef.h>
 
+#include <cmath>
 #include <limits>
 #include <type_traits>
 
 #include "third_party/base/numerics/safe_conversions_impl.h"
 
-#if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__))
+#if defined(__ARMEL__) && !defined(__native_client__)
 #include "third_party/base/numerics/safe_conversions_arm_impl.h"
 #define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS (1)
 #else
 #define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS (0)
 #endif
 
+#if !BASE_NUMERICS_DISABLE_OSTREAM_OPERATORS
+#include <ostream>
+#endif
+
 namespace pdfium {
 namespace base {
 namespace internal {
@@ -26,7 +31,7 @@
 #if !BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
 template <typename Dst, typename Src>
 struct SaturateFastAsmOp {
-  static const bool is_supported = false;
+  static constexpr bool is_supported = false;
   static constexpr Dst Do(Src) {
     // Force a compile failure if instantiated.
     return CheckOnFailure::template HandleFailure<Dst>();
@@ -39,7 +44,7 @@
 // eke out better performance than range checking.
 template <typename Dst, typename Src, typename Enable = void>
 struct IsValueInRangeFastOp {
-  static const bool is_supported = false;
+  static constexpr bool is_supported = false;
   static constexpr bool Do(Src value) {
     // Force a compile failure if instantiated.
     return CheckOnFailure::template HandleFailure<bool>();
@@ -55,7 +60,7 @@
         std::is_integral<Dst>::value && std::is_integral<Src>::value &&
         std::is_signed<Dst>::value && std::is_signed<Src>::value &&
         !IsTypeInRangeForNumericType<Dst, Src>::value>::type> {
-  static const bool is_supported = true;
+  static constexpr bool is_supported = true;
 
   static constexpr bool Do(Src value) {
     // Just downcast to the smaller type, sign extend it back to the original
@@ -73,7 +78,7 @@
         std::is_integral<Dst>::value && std::is_integral<Src>::value &&
         !std::is_signed<Dst>::value && std::is_signed<Src>::value &&
         !IsTypeInRangeForNumericType<Dst, Src>::value>::type> {
-  static const bool is_supported = true;
+  static constexpr bool is_supported = true;
 
   static constexpr bool Do(Src value) {
     // We cast a signed as unsigned to overflow negative values to the top,
@@ -152,7 +157,7 @@
 // Arm, we can use the optimized saturation instructions.
 template <typename Dst, typename Src, typename Enable = void>
 struct SaturateFastOp {
-  static const bool is_supported = false;
+  static constexpr bool is_supported = false;
   static constexpr Dst Do(Src value) {
     // Force a compile failure if instantiated.
     return CheckOnFailure::template HandleFailure<Dst>();
@@ -166,8 +171,10 @@
     typename std::enable_if<std::is_integral<Src>::value &&
                             std::is_integral<Dst>::value &&
                             SaturateFastAsmOp<Dst, Src>::is_supported>::type> {
-  static const bool is_supported = true;
-  static Dst Do(Src value) { return SaturateFastAsmOp<Dst, Src>::Do(value); }
+  static constexpr bool is_supported = true;
+  static constexpr Dst Do(Src value) {
+    return SaturateFastAsmOp<Dst, Src>::Do(value);
+  }
 };
 
 template <typename Dst, typename Src>
@@ -177,12 +184,12 @@
     typename std::enable_if<std::is_integral<Src>::value &&
                             std::is_integral<Dst>::value &&
                             !SaturateFastAsmOp<Dst, Src>::is_supported>::type> {
-  static const bool is_supported = true;
-  static Dst Do(Src value) {
+  static constexpr bool is_supported = true;
+  static constexpr Dst Do(Src value) {
     // The exact order of the following is structured to hit the correct
     // optimization heuristics across compilers. Do not change without
     // checking the emitted code.
-    Dst saturated = CommonMaxOrMin<Dst, Src>(
+    const Dst saturated = CommonMaxOrMin<Dst, Src>(
         IsMaxInRangeForNumericType<Dst, Src>() ||
         (!IsMinInRangeForNumericType<Dst, Src>() && IsValueNegative(value)));
     return BASE_NUMERICS_LIKELY(IsValueInRangeForNumericType<Dst>(value))
@@ -194,14 +201,13 @@
 // saturated_cast<> is analogous to static_cast<> for numeric types, except
 // that the specified numeric conversion will saturate by default rather than
 // overflow or underflow, and NaN assignment to an integral will return 0.
-// All boundary condition behaviors can be overriden with a custom handler.
+// All boundary condition behaviors can be overridden with a custom handler.
 template <typename Dst,
           template <typename> class SaturationHandler = SaturationDefaultLimits,
           typename Src>
 constexpr Dst saturated_cast(Src value) {
   using SrcType = typename UnderlyingType<Src>::type;
-  return !IsCompileTimeConstant(value) &&
-                 SaturateFastOp<Dst, SrcType>::is_supported &&
+  return !IsConstantEvaluated() && SaturateFastOp<Dst, SrcType>::is_supported &&
                  std::is_same<SaturationHandler<Dst>,
                               SaturationDefaultLimits<Dst>>::value
              ? SaturateFastOp<Dst, SrcType>::Do(static_cast<SrcType>(value))
@@ -237,7 +243,7 @@
 // Some wrappers to statically check that a type is in range.
 template <typename Dst, typename Src, class Enable = void>
 struct IsNumericRangeContained {
-  static const bool value = false;
+  static constexpr bool value = false;
 };
 
 template <typename Dst, typename Src>
@@ -246,8 +252,9 @@
     Src,
     typename std::enable_if<ArithmeticOrUnderlyingEnum<Dst>::value &&
                             ArithmeticOrUnderlyingEnum<Src>::value>::type> {
-  static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
-                            NUMERIC_RANGE_CONTAINED;
+  static constexpr bool value =
+      StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
+      NUMERIC_RANGE_CONTAINED;
 };
 
 // StrictNumeric implements compile time range checking between numeric types by
@@ -301,7 +308,8 @@
   const T value_;
 };
 
-// Convience wrapper returns a StrictNumeric from the provided arithmetic type.
+// Convenience wrapper returns a StrictNumeric from the provided arithmetic
+// type.
 template <typename T>
 constexpr StrictNumeric<typename UnderlyingType<T>::type> MakeStrictNum(
     const T value) {
@@ -329,18 +337,45 @@
 using internal::as_signed;
 using internal::as_unsigned;
 using internal::checked_cast;
-using internal::strict_cast;
-using internal::saturated_cast;
-using internal::SafeUnsignedAbs;
-using internal::StrictNumeric;
-using internal::MakeStrictNum;
-using internal::IsValueInRangeForNumericType;
 using internal::IsTypeInRangeForNumericType;
+using internal::IsValueInRangeForNumericType;
 using internal::IsValueNegative;
+using internal::MakeStrictNum;
+using internal::SafeUnsignedAbs;
+using internal::saturated_cast;
+using internal::strict_cast;
+using internal::StrictNumeric;
 
 // Explicitly make a shorter size_t alias for convenience.
 using SizeT = StrictNumeric<size_t>;
 
+// floating -> integral conversions that saturate and thus can actually return
+// an integral type.  In most cases, these should be preferred over the std::
+// versions.
+template <typename Dst = int,
+          typename Src,
+          typename = std::enable_if_t<std::is_integral<Dst>::value &&
+                                      std::is_floating_point<Src>::value>>
+Dst ClampFloor(Src value) {
+  return saturated_cast<Dst>(std::floor(value));
+}
+template <typename Dst = int,
+          typename Src,
+          typename = std::enable_if_t<std::is_integral<Dst>::value &&
+                                      std::is_floating_point<Src>::value>>
+Dst ClampCeil(Src value) {
+  return saturated_cast<Dst>(std::ceil(value));
+}
+template <typename Dst = int,
+          typename Src,
+          typename = std::enable_if_t<std::is_integral<Dst>::value &&
+                                      std::is_floating_point<Src>::value>>
+Dst ClampRound(Src value) {
+  const Src rounded =
+      (value >= 0.0f) ? std::floor(value + 0.5f) : std::ceil(value - 0.5f);
+  return saturated_cast<Dst>(rounded);
+}
+
 }  // namespace base
 }  // namespace pdfium
 
diff --git a/third_party/base/numerics/safe_conversions_arm_impl.h b/third_party/base/numerics/safe_conversions_arm_impl.h
index f5e4c4e..426118a 100644
--- a/third_party/base/numerics/safe_conversions_arm_impl.h
+++ b/third_party/base/numerics/safe_conversions_arm_impl.h
@@ -19,8 +19,8 @@
 template <typename Dst, typename Src>
 struct SaturateFastAsmOp {
   static constexpr bool is_supported =
-      std::is_signed<Src>::value && std::is_integral<Dst>::value &&
-      std::is_integral<Src>::value &&
+      kEnableAsmCode && std::is_signed<Src>::value &&
+      std::is_integral<Dst>::value && std::is_integral<Src>::value &&
       IntegerBitsPlusSign<Src>::value <= IntegerBitsPlusSign<int32_t>::value &&
       IntegerBitsPlusSign<Dst>::value <= IntegerBitsPlusSign<int32_t>::value &&
       !IsTypeInRangeForNumericType<Dst, Src>::value;
diff --git a/third_party/base/numerics/safe_conversions_impl.h b/third_party/base/numerics/safe_conversions_impl.h
index 116190d..4d8a7b7 100644
--- a/third_party/base/numerics/safe_conversions_impl.h
+++ b/third_party/base/numerics/safe_conversions_impl.h
@@ -86,30 +86,18 @@
              : static_cast<UnsignedT>(value);
 }
 
-// This allows us to switch paths on known compile-time constants.
-#if defined(__clang__) || defined(__GNUC__)
-constexpr bool CanDetectCompileTimeConstant() {
-  return true;
-}
-template <typename T>
-constexpr bool IsCompileTimeConstant(const T v) {
-  return __builtin_constant_p(v);
-}
+// TODO(jschuh): Switch to std::is_constant_evaluated() once C++20 is supported.
+// Alternately, the usage could be restructured for "consteval if" in C++23.
+#define IsConstantEvaluated() (__builtin_is_constant_evaluated())
+
+// TODO(jschuh): Debug builds don't reliably propagate constants, so we restrict
+// some accelerated runtime paths to release builds until this can be forced
+// with consteval support in C++20 or C++23.
+#if defined(NDEBUG)
+constexpr bool kEnableAsmCode = true;
 #else
-constexpr bool CanDetectCompileTimeConstant() {
-  return false;
-}
-template <typename T>
-constexpr bool IsCompileTimeConstant(const T) {
-  return false;
-}
+constexpr bool kEnableAsmCode = false;
 #endif
-template <typename T>
-constexpr bool MustTreatAsConstexpr(const T v) {
-  // Either we can't detect a compile-time constant, and must always use the
-  // constexpr path, or we know we have a compile-time constant.
-  return !CanDetectCompileTimeConstant() || IsCompileTimeConstant(v);
-}
 
 // Forces a crash, like a CHECK(false). Used for numeric boundary errors.
 // Also used in a constexpr template to trigger a compilation failure on
@@ -194,7 +182,7 @@
  public:
   constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
       : is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {}
-  constexpr RangeCheck() : is_underflow_(0), is_overflow_(0) {}
+  constexpr RangeCheck() : is_underflow_(false), is_overflow_(false) {}
   constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; }
   constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; }
   constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; }
@@ -277,7 +265,8 @@
 
 template <typename Dst,
           typename Src,
-          template <typename> class Bounds,
+          template <typename>
+          class Bounds,
           IntegerRepresentation DstSign = std::is_signed<Dst>::value
                                               ? INTEGER_REPRESENTATION_SIGNED
                                               : INTEGER_REPRESENTATION_UNSIGNED,
@@ -295,7 +284,8 @@
 // Same sign narrowing: The range is contained for normal limits.
 template <typename Dst,
           typename Src,
-          template <typename> class Bounds,
+          template <typename>
+          class Bounds,
           IntegerRepresentation DstSign,
           IntegerRepresentation SrcSign>
 struct DstRangeRelationToSrcRangeImpl<Dst,
@@ -379,9 +369,17 @@
     using SrcLimits = std::numeric_limits<Src>;
     using DstLimits = NarrowingRange<Dst, Src, Bounds>;
     using Promotion = decltype(Src() + Dst());
+    bool ge_zero = false;
+    // Converting floating-point to integer will discard fractional part, so
+    // values in (-1.0, -0.0) will truncate to 0 and fit in Dst.
+    if (std::is_floating_point<Src>::value) {
+      ge_zero = value > Src(-1);
+    } else {
+      ge_zero = value >= Src(0);
+    }
     return RangeCheck(
-        value >= Src(0) && (DstLimits::lowest() == 0 ||
-                            static_cast<Dst>(value) >= DstLimits::lowest()),
+        ge_zero && (DstLimits::lowest() == 0 ||
+                    static_cast<Dst>(value) >= DstLimits::lowest()),
         static_cast<Promotion>(SrcLimits::max()) <=
                 static_cast<Promotion>(DstLimits::max()) ||
             static_cast<Promotion>(value) <=
@@ -693,9 +691,8 @@
                           const RangeCheck l_range,
                           const RangeCheck r_range) {
   return l_range.IsUnderflow() || r_range.IsOverflow() ||
-         (l_range == r_range &&
-          static_cast<decltype(lhs + rhs)>(lhs) <
-              static_cast<decltype(lhs + rhs)>(rhs));
+         (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <
+                                    static_cast<decltype(lhs + rhs)>(rhs));
 }
 
 template <typename L, typename R>
@@ -714,9 +711,8 @@
                                  const RangeCheck l_range,
                                  const RangeCheck r_range) {
   return l_range.IsUnderflow() || r_range.IsOverflow() ||
-         (l_range == r_range &&
-          static_cast<decltype(lhs + rhs)>(lhs) <=
-              static_cast<decltype(lhs + rhs)>(rhs));
+         (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <=
+                                    static_cast<decltype(lhs + rhs)>(rhs));
 }
 
 template <typename L, typename R>
@@ -735,9 +731,8 @@
                              const RangeCheck l_range,
                              const RangeCheck r_range) {
   return l_range.IsOverflow() || r_range.IsUnderflow() ||
-         (l_range == r_range &&
-          static_cast<decltype(lhs + rhs)>(lhs) >
-              static_cast<decltype(lhs + rhs)>(rhs));
+         (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >
+                                    static_cast<decltype(lhs + rhs)>(rhs));
 }
 
 template <typename L, typename R>
@@ -756,9 +751,8 @@
                                     const RangeCheck l_range,
                                     const RangeCheck r_range) {
   return l_range.IsOverflow() || r_range.IsUnderflow() ||
-         (l_range == r_range &&
-          static_cast<decltype(lhs + rhs)>(lhs) >=
-              static_cast<decltype(lhs + rhs)>(rhs));
+         (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >=
+                                    static_cast<decltype(lhs + rhs)>(rhs));
 }
 
 template <typename L, typename R>
diff --git a/third_party/base/numerics/safe_math_arm_impl.h b/third_party/base/numerics/safe_math_arm_impl.h
index 3291e74..cea9632 100644
--- a/third_party/base/numerics/safe_math_arm_impl.h
+++ b/third_party/base/numerics/safe_math_arm_impl.h
@@ -6,7 +6,6 @@
 #define THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_
 
 #include <cassert>
-#include <limits>
 #include <type_traits>
 
 #include "third_party/base/numerics/safe_conversions.h"
@@ -18,9 +17,10 @@
 template <typename T, typename U>
 struct CheckedMulFastAsmOp {
   static const bool is_supported =
-      FastIntegerArithmeticPromotion<T, U>::is_contained;
+      kEnableAsmCode && FastIntegerArithmeticPromotion<T, U>::is_contained;
 
-  // The following is much more efficient than the Clang and GCC builtins for
+  // The following is not an assembler routine and is thus constexpr safe, it
+  // just emits much more efficient code than the Clang and GCC builtins for
   // performing overflow-checked multiplication when a twice wider type is
   // available. The below compiles down to 2-3 instructions, depending on the
   // width of the types in use.
@@ -32,20 +32,22 @@
   //    asr     r2, r1, #16
   //    cmp     r2, r1, asr #15
   template <typename V>
-  __attribute__((always_inline)) static bool Do(T x, U y, V* result) {
+  static constexpr bool Do(T x, U y, V* result) {
     using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
     Promotion presult;
 
     presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
+    if (!IsValueInRangeForNumericType<V>(presult))
+      return false;
     *result = static_cast<V>(presult);
-    return IsValueInRangeForNumericType<V>(presult);
+    return true;
   }
 };
 
 template <typename T, typename U>
 struct ClampedAddFastAsmOp {
   static const bool is_supported =
-      BigEnoughPromotion<T, U>::is_contained &&
+      kEnableAsmCode && BigEnoughPromotion<T, U>::is_contained &&
       IsTypeInRangeForNumericType<
           int32_t,
           typename BigEnoughPromotion<T, U>::type>::value;
@@ -71,7 +73,7 @@
 template <typename T, typename U>
 struct ClampedSubFastAsmOp {
   static const bool is_supported =
-      BigEnoughPromotion<T, U>::is_contained &&
+      kEnableAsmCode && BigEnoughPromotion<T, U>::is_contained &&
       IsTypeInRangeForNumericType<
           int32_t,
           typename BigEnoughPromotion<T, U>::type>::value;
@@ -96,7 +98,8 @@
 
 template <typename T, typename U>
 struct ClampedMulFastAsmOp {
-  static const bool is_supported = CheckedMulFastAsmOp<T, U>::is_supported;
+  static const bool is_supported =
+      kEnableAsmCode && CheckedMulFastAsmOp<T, U>::is_supported;
 
   template <typename V>
   __attribute__((always_inline)) static V Do(T x, U y) {
@@ -105,9 +108,9 @@
     if (!IsIntegerArithmeticSafe<int32_t, T, U>::value &&
         !IsIntegerArithmeticSafe<uint32_t, T, U>::value) {
       V result;
-      if (CheckedMulFastAsmOp<T, U>::Do(x, y, &result))
-        return result;
-      return CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
+      return CheckedMulFastAsmOp<T, U>::Do(x, y, &result)
+                 ? result
+                 : CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
     }
 
     assert((FastIntegerArithmeticPromotion<T, U>::is_contained));
diff --git a/third_party/base/numerics/safe_math_shared_impl.h b/third_party/base/numerics/safe_math_shared_impl.h
index 8c06882..871906d 100644
--- a/third_party/base/numerics/safe_math_shared_impl.h
+++ b/third_party/base/numerics/safe_math_shared_impl.h
@@ -15,17 +15,18 @@
 #include <limits>
 #include <type_traits>
 
+#include "build/build_config.h"
 #include "third_party/base/numerics/safe_conversions.h"
 
-#ifdef __asmjs__
+#if BUILDFLAG(IS_ASMJS)
 // Optimized safe math instructions are incompatible with asmjs.
 #define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
 // Where available use builtin math overflow support on Clang and GCC.
-#elif !defined(__native_client__) &&                         \
-      ((defined(__clang__) &&                                \
-        ((__clang_major__ > 3) ||                            \
-         (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
-       (defined(__GNUC__) && __GNUC__ >= 5))
+#elif !defined(__native_client__) &&                       \
+    ((defined(__clang__) &&                                \
+      ((__clang_major__ > 3) ||                            \
+       (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
+     (defined(__GNUC__) && __GNUC__ >= 5))
 #include "third_party/base/numerics/safe_math_clang_gcc_impl.h"
 #define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
 #else
@@ -132,7 +133,7 @@
 // Wrap the unary operations to allow SFINAE when instantiating integrals versus
 // floating points. These don't perform any overflow checking. Rather, they
 // exhibit well-defined overflow semantics and rely on the caller to detect
-// if an overflow occured.
+// if an overflow occurred.
 
 template <typename T,
           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
@@ -178,38 +179,13 @@
   using type = typename math::result_type;
 };
 
-// These variadic templates work out the return types.
-// TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
-template <template <typename, typename, typename> class M,
-          typename L,
-          typename R,
-          typename... Args>
-struct ResultType;
-
-template <template <typename, typename, typename> class M,
-          typename L,
-          typename R>
-struct ResultType<M, L, R> {
-  using type = typename MathWrapper<M, L, R>::type;
-};
-
-template <template <typename, typename, typename> class M,
-          typename L,
-          typename R,
-          typename... Args>
-struct ResultType {
-  using type =
-      typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type;
-};
-
 // The following macros are just boilerplate for the standard arithmetic
 // operator overloads and variadic function templates. A macro isn't the nicest
 // solution, but it beats rewriting these over and over again.
 #define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)       \
   template <typename L, typename R, typename... Args>                   \
-  constexpr CLASS##Numeric<                                             \
-      typename ResultType<CLASS##OP_NAME##Op, L, R, Args...>::type>     \
-      CL_ABBR##OP_NAME(const L lhs, const R rhs, const Args... args) {  \
+  constexpr auto CL_ABBR##OP_NAME(const L lhs, const R rhs,             \
+                                  const Args... args) {                 \
     return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
                                                               args...); \
   }