Implement CRYPTO_addc_* and CRYPTO_subc_* in C++ more straightforwardly

We don't need partial specialization. Plain overflows work just fine. We
probably can just use overloads and remove the type-suffixed functions
and everything, here and in our constant-time functions and whatnot, but
I've left that alone for now.

Change-Id: I701f40edac7457a1a0e3702644b3f7ba7bd3daea
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/73747
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/crypto/internal.h b/crypto/internal.h
index 6821618..8c1900b 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -1558,49 +1558,33 @@
 // bit. |carry| must be zero or one.
 #if OPENSSL_HAS_BUILTIN(__builtin_addc)
 
-template <typename T>
-struct CRYPTO_addc_impl {
-  static_assert(sizeof(T) == 0, "Unsupported type for addc operation");
-};
+inline unsigned int CRYPTO_addc_impl(unsigned int x, unsigned int y,
+                                     unsigned int carry,
+                                     unsigned int *out_carry) {
+  return __builtin_addc(x, y, carry, out_carry);
+}
 
-template <>
-struct CRYPTO_addc_impl<unsigned int> {
-  static unsigned int add(unsigned int x, unsigned int y, unsigned int carry,
-                          unsigned int *out_carry) {
-    return __builtin_addc(x, y, carry, out_carry);
-  }
-};
+inline unsigned long CRYPTO_addc_impl(unsigned long x, unsigned long y,
+                                      unsigned long carry,
+                                      unsigned long *out_carry) {
+  return __builtin_addcl(x, y, carry, out_carry);
+}
 
-template <>
-struct CRYPTO_addc_impl<unsigned long> {
-  static unsigned long add(unsigned long x, unsigned long y,
-                           unsigned long carry, unsigned long *out_carry) {
-    return __builtin_addcl(x, y, carry, out_carry);
-  }
-};
-
-template <>
-struct CRYPTO_addc_impl<unsigned long long> {
-  static unsigned long long add(unsigned long long x, unsigned long long y,
-                                unsigned long long carry,
-                                unsigned long long *out_carry) {
-    return __builtin_addcll(x, y, carry, out_carry);
-  }
-};
-
-template <typename T>
-inline T CRYPTO_addc(T x, T y, T carry, T *out_carry) {
-  return CRYPTO_addc_impl<T>::add(x, y, carry, out_carry);
+inline unsigned long long CRYPTO_addc_impl(unsigned long long x,
+                                           unsigned long long y,
+                                           unsigned long long carry,
+                                           unsigned long long *out_carry) {
+  return __builtin_addcll(x, y, carry, out_carry);
 }
 
 inline uint32_t CRYPTO_addc_u32(uint32_t x, uint32_t y, uint32_t carry,
                                 uint32_t *out_carry) {
-  return CRYPTO_addc(x, y, carry, out_carry);
+  return CRYPTO_addc_impl(x, y, carry, out_carry);
 }
 
 inline uint64_t CRYPTO_addc_u64(uint64_t x, uint64_t y, uint64_t carry,
                                 uint64_t *out_carry) {
-  return CRYPTO_addc(x, y, carry, out_carry);
+  return CRYPTO_addc_impl(x, y, carry, out_carry);
 }
 
 #else
@@ -1638,49 +1622,33 @@
 // bit. |borrow| must be zero or one.
 #if OPENSSL_HAS_BUILTIN(__builtin_subc)
 
-template <typename T>
-struct CRYPTO_subc_impl {
-  static_assert(sizeof(T) == 0, "Unsupported type for subc operation");
-};
+inline unsigned int CRYPTO_subc_impl(unsigned int x, unsigned int y,
+                                     unsigned int borrow,
+                                     unsigned int *out_borrow) {
+  return __builtin_subc(x, y, borrow, out_borrow);
+}
 
-template <>
-struct CRYPTO_subc_impl<unsigned int> {
-  static unsigned int sub(unsigned int x, unsigned int y, unsigned int borrow,
-                          unsigned int *out_borrow) {
-    return __builtin_subc(x, y, borrow, out_borrow);
-  }
-};
+inline unsigned long CRYPTO_subc_impl(unsigned long x, unsigned long y,
+                                      unsigned long borrow,
+                                      unsigned long *out_borrow) {
+  return __builtin_subcl(x, y, borrow, out_borrow);
+}
 
-template <>
-struct CRYPTO_subc_impl<unsigned long> {
-  static unsigned long sub(unsigned long x, unsigned long y,
-                           unsigned long borrow, unsigned long *out_borrow) {
-    return __builtin_subcl(x, y, borrow, out_borrow);
-  }
-};
-
-template <>
-struct CRYPTO_subc_impl<unsigned long long> {
-  static unsigned long long sub(unsigned long long x, unsigned long long y,
-                                unsigned long long borrow,
-                                unsigned long long *out_borrow) {
-    return __builtin_subcll(x, y, borrow, out_borrow);
-  }
-};
-
-template <typename T>
-inline T CRYPTO_subc(T x, T y, T borrow, T *out_borrow) {
-  return CRYPTO_subc_impl<T>::sub(x, y, borrow, out_borrow);
+inline unsigned long long CRYPTO_subc_impl(unsigned long long x,
+                                           unsigned long long y,
+                                           unsigned long long borrow,
+                                           unsigned long long *out_borrow) {
+  return __builtin_subcll(x, y, borrow, out_borrow);
 }
 
 inline uint32_t CRYPTO_subc_u32(uint32_t x, uint32_t y, uint32_t borrow,
                                 uint32_t *out_borrow) {
-  return CRYPTO_subc(x, y, borrow, out_borrow);
+  return CRYPTO_subc_impl(x, y, borrow, out_borrow);
 }
 
 inline uint64_t CRYPTO_subc_u64(uint64_t x, uint64_t y, uint64_t borrow,
                                 uint64_t *out_borrow) {
-  return CRYPTO_subc(x, y, borrow, out_borrow);
+  return CRYPTO_subc_impl(x, y, borrow, out_borrow);
 }
 
 #else