Require C++17

Update-Note: BoringSSL now requires a C++17 toolchain. This aligns with
Google's Foundational C++ Support Policy as it has now been 10 years
since C++14 was published. See
https://opensource.google/documentation/policies/cplusplus-support

Bug: 42290600
Change-Id: I54b914ccdde2b61a76a4ebfbe67c1fb28f7ba6ac
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/74467
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/.bcr/presubmit.yml b/.bcr/presubmit.yml
index 4c03ba7..32813ba 100644
--- a/.bcr/presubmit.yml
+++ b/.bcr/presubmit.yml
@@ -21,7 +21,7 @@
     bazel: ${{ bazel }}
     build_targets: *build_targets
     build_flags: &macos_workaround
-      - '--cxxopt=-std=c++14'
+      - '--cxxopt=-std=c++17'
       - '--sandbox_block_path=/usr/local'
 bcr_test_module:
   module_path: util/bazel-example
diff --git a/BUILDING.md b/BUILDING.md
index 8b6203b..e7e7f0e 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -25,7 +25,7 @@
     by CMake, it may be configured explicitly by setting
     `CMAKE_ASM_NASM_COMPILER`.
 
-  * Compilers for C11 and C++14, or later, are required. On Windows, MSVC from
+  * Compilers for C11 and C++17, or later, are required. On Windows, MSVC from
     Visual Studio 2022 or later with Windows 10 SDK 2104 or later are
     supported, but using the latest versions is recommended. Recent versions of
     GCC (6.1+) and Clang should work on non-Windows platforms, and maybe on
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 38d63db..5d96aad 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -97,7 +97,7 @@
   set(EMSCRIPTEN 1)
 endif()
 
-set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 set(CMAKE_C_STANDARD 11)
 set(CMAKE_C_STANDARD_REQUIRED ON)
@@ -689,13 +689,9 @@
 target_link_libraries(pki_test test_support_lib boringssl_gtest pki crypto)
 add_dependencies(all_tests pki_test)
 
-# The PKI library requires C++17, but we haven't required this everywhere yet.
-# TODO(crbug.com/42290600): Remove the C++17 bits.
 set_target_properties(
   pki pki_test
   PROPERTIES
-  CXX_STANDARD 17
-  CXX_STANDARD_REQUIRED YES
   COMPILE_FLAGS "${PKI_CXX_FLAGS}")
 
 add_executable(bssl ${BSSL_SOURCES})
@@ -718,10 +714,6 @@
     set_target_properties(
       Fuzzer PROPERTIES
       COMPILE_FLAGS "-Wno-shadow -Wno-format-nonliteral -Wno-missing-prototypes -fsanitize-coverage=0"
-      # libFuzzer requires C++17, but we haven't required this everywhere yet.
-      # TODO(crbug.com/42290600): Remove this.
-      CXX_STANDARD 17
-      CXX_STANDARD_REQUIRED TRUE
     )
   endif()
 
diff --git a/crypto/fipsmodule/mldsa/mldsa.cc.inc b/crypto/fipsmodule/mldsa/mldsa.cc.inc
index e9166b5..2495a3e 100644
--- a/crypto/fipsmodule/mldsa/mldsa.cc.inc
+++ b/crypto/fipsmodule/mldsa/mldsa.cc.inc
@@ -51,126 +51,85 @@
 // Constants that vary depending on ML-DSA size.
 //
 // These are implemented as templates which take the K parameter to distinguish
-// the ML-DSA sizes. (At the time of writing, `if constexpr` was not available.)
-//
-// TODO(crbug.com/42290600): Switch this to `if constexpr` when C++17 is
-// available.
+// the ML-DSA sizes.
 
 template <int K>
-constexpr size_t public_key_bytes();
-
-template <>
-constexpr size_t public_key_bytes<6>() {
-  return BCM_MLDSA65_PUBLIC_KEY_BYTES;
-}
-
-template <>
-constexpr size_t public_key_bytes<8>() {
-  return BCM_MLDSA87_PUBLIC_KEY_BYTES;
+constexpr size_t public_key_bytes() {
+  if constexpr (K == 6) {
+    return BCM_MLDSA65_PUBLIC_KEY_BYTES;
+  } else if constexpr (K == 8) {
+    return BCM_MLDSA87_PUBLIC_KEY_BYTES;
+  }
 }
 
 template <int K>
-constexpr size_t signature_bytes();
-
-template <>
-constexpr size_t signature_bytes<6>() {
-  return BCM_MLDSA65_SIGNATURE_BYTES;
-}
-
-template <>
-constexpr size_t signature_bytes<8>() {
-  return BCM_MLDSA87_SIGNATURE_BYTES;
+constexpr size_t signature_bytes() {
+  if constexpr (K == 6) {
+    return BCM_MLDSA65_SIGNATURE_BYTES;
+  } else if constexpr (K == 8) {
+    return BCM_MLDSA87_SIGNATURE_BYTES;
+  }
 }
 
 template <int K>
-constexpr int tau();
-
-template <>
-constexpr int tau<6>() {
-  return 49;
-}
-
-template <>
-constexpr int tau<8>() {
-  return 60;
+constexpr int tau() {
+  if constexpr (K == 6) {
+    return 49;
+  } else if constexpr (K == 8) {
+    return 60;
+  }
 }
 
 template <int K>
-constexpr int lambda_bytes();
-
-template <>
-constexpr int lambda_bytes<6>() {
-  return 192 / 8;
-}
-
-template <>
-constexpr int lambda_bytes<8>() {
-  return 256 / 8;
+constexpr int lambda_bytes() {
+  if constexpr (K == 6) {
+    return 192 / 8;
+  } else if constexpr (K == 8) {
+    return 256 / 8;
+  }
 }
 
 template <int K>
-constexpr int gamma1();
-
-template <>
-constexpr int gamma1<6>() {
-  return 1 << 19;
-}
-
-template <>
-constexpr int gamma1<8>() {
-  return 1 << 19;
+constexpr int gamma1() {
+  if constexpr (K == 6 || K == 8) {
+    return 1 << 19;
+  }
 }
 
 template <int K>
-constexpr int beta();
-
-template <>
-constexpr int beta<6>() {
-  return 196;
-}
-
-template <>
-constexpr int beta<8>() {
-  return 120;
+constexpr int beta() {
+  if constexpr (K == 6) {
+    return 196;
+  } else if constexpr (K == 8) {
+    return 120;
+  }
 }
 
 template <int K>
-constexpr int omega();
-
-template <>
-constexpr int omega<6>() {
-  return 55;
-}
-
-template <>
-constexpr int omega<8>() {
-  return 75;
+constexpr int omega() {
+  if constexpr (K == 6) {
+    return 55;
+  } else if constexpr (K == 8) {
+    return 75;
+  }
 }
 
 template <int K>
-constexpr int eta();
-
-template <>
-constexpr int eta<6>() {
-  return 4;
-}
-
-template <>
-constexpr int eta<8>() {
-  return 2;
+constexpr int eta() {
+  if constexpr (K == 6) {
+    return 4;
+  } else if constexpr (K == 8) {
+    return 2;
+  }
 }
 
 template <int K>
-constexpr int plus_minus_eta_bitlen();
-
-template <>
-constexpr int plus_minus_eta_bitlen<6>() {
-  return 4;
-}
-
-template <>
-constexpr int plus_minus_eta_bitlen<8>() {
-  return 3;
+constexpr int plus_minus_eta_bitlen() {
+  if constexpr (K == 6) {
+    return 4;
+  } else if constexpr (K == 8) {
+    return 3;
+  }
 }
 
 // Fundamental types.
diff --git a/crypto/rand_extra/urandom_test.cc b/crypto/rand_extra/urandom_test.cc
index fa05f4c..dcf9cc5 100644
--- a/crypto/rand_extra/urandom_test.cc
+++ b/crypto/rand_extra/urandom_test.cc
@@ -15,6 +15,8 @@
 #include <gtest/gtest.h>
 #include <stdlib.h>
 
+#include <optional>
+
 #include <openssl/bytestring.h>
 #include <openssl/ctrdrbg.h>
 #include <openssl/rand.h>
@@ -305,30 +307,6 @@
 
 #endif
 
-// SyscallResult is like std::optional<int>.
-// TODO: use std::optional when we can use C++17.
-class SyscallResult {
- public:
-  SyscallResult &operator=(int value) {
-    has_value_ = true;
-    value_ = value;
-    return *this;
-  }
-
-  int value() const {
-    if (!has_value_) {
-      abort();
-    }
-    return value_;
-  }
-
-  bool has_value() const { return has_value_; }
-
- private:
-  bool has_value_ = false;
-  int value_ = 0;
-};
-
 // memcpy_to_remote copies |n| bytes from |in_src| in the local address space,
 // to |dest| in the address space of |child_pid|.
 static void memcpy_to_remote(int child_pid, uint64_t dest, const void *in_src,
@@ -471,7 +449,7 @@
     // force_result is unset to indicate that the system call should run
     // normally. Otherwise it's, e.g. -EINVAL, to indicate that the system call
     // should not run and that the given value should be injected on return.
-    SyscallResult force_result;
+    std::optional<int> force_result;
 
     switch (regs.syscall) {
       case __NR_getrandom:
diff --git a/crypto/test/file_util.cc b/crypto/test/file_util.cc
index f086ed0..0fcdb3f 100644
--- a/crypto/test/file_util.cc
+++ b/crypto/test/file_util.cc
@@ -123,8 +123,7 @@
   path_ = path;
 #else
   std::string path = temp_dir + "bssl_tmp_file.XXXXXX";
-  // TODO(davidben): Use |path.data()| when we require C++17.
-  int fd = mkstemp(&path[0]);
+  int fd = mkstemp(path.data());
   if (fd < 0) {
     perror("Could not create temporary file");
     return false;
@@ -208,8 +207,7 @@
   }
 #else
   path += "bssl_tmp_dir.XXXXXX";
-  // TODO(davidben): Use |path.data()| when we require C++17.
-  if (mkdtemp(&path[0]) == nullptr) {
+  if (mkdtemp(path.data()) == nullptr) {
     perror("Could not make temporary directory");
     return false;
   }
diff --git a/include/openssl/span.h b/include/openssl/span.h
index 9e5ff7c..46c5c6c 100644
--- a/include/openssl/span.h
+++ b/include/openssl/span.h
@@ -24,11 +24,8 @@
 #include <stdlib.h>
 
 #include <algorithm>
-#include <type_traits>
-
-#if __cplusplus >= 201703L
 #include <string_view>
-#endif
+#include <type_traits>
 
 #if defined(__has_include)
 #if __has_include(<version>)
@@ -74,12 +71,10 @@
 
 // Heuristically test whether C is a container type that can be converted into
 // a Span<T> by checking for data() and size() member functions.
-//
-// TODO(davidben): Require C++17 support for std::is_convertible_v, etc.
 template <typename C, typename T>
 using EnableIfContainer = std::enable_if_t<
-    std::is_convertible<decltype(std::declval<C>().data()), T *>::value &&
-    std::is_integral<decltype(std::declval<C>().size())>::value>;
+    std::is_convertible_v<decltype(std::declval<C>().data()), T *> &&
+    std::is_integral_v<decltype(std::declval<C>().size())>>;
 
 }  // namespace internal
 
@@ -210,7 +205,6 @@
 template <typename T>
 const size_t Span<T>::npos;
 
-#if __cplusplus >= 201703L
 template <typename T>
 Span(T *, size_t) -> Span<T>;
 template <typename T, size_t size>
@@ -220,10 +214,7 @@
     typename T = std::remove_pointer_t<decltype(std::declval<C>().data())>,
     typename = internal::EnableIfContainer<C, T>>
 Span(C &) -> Span<T>;
-#endif
 
-// C++17 callers can instead rely on CTAD and the deduction guides defined
-// above.
 template <typename T>
 constexpr Span<T> MakeSpan(T *ptr, size_t size) {
   return Span<T>(ptr, size);
@@ -255,7 +246,6 @@
   return array;
 }
 
-#if __cplusplus >= 201703L
 inline Span<const uint8_t> StringAsBytes(std::string_view s) {
   return MakeConstSpan(reinterpret_cast<const uint8_t *>(s.data()), s.size());
 }
@@ -263,7 +253,6 @@
 inline std::string_view BytesAsStringView(bssl::Span<const uint8_t> b) {
   return std::string_view(reinterpret_cast<const char *>(b.data()), b.size());
 }
-#endif
 
 BSSL_NAMESPACE_END
 
diff --git a/ssl/internal.h b/ssl/internal.h
index 7dc522d..7c91643 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -188,53 +188,6 @@
 
 // C++ utilities.
 
-// Fill-ins for various functions in C++17.
-// TODO(crbug.com/42290600): Replace these with the standard ones when we
-// require C++17.
-
-template <typename ForwardIt>
-ForwardIt cxx17_uninitialized_default_construct_n(ForwardIt first, size_t n) {
-  using T = typename std::iterator_traits<ForwardIt>::value_type;
-  while (n > 0) {
-    new (std::addressof(*first)) T;
-    first++;
-    n--;
-  }
-  return first;
-}
-
-template <typename ForwardIt>
-ForwardIt cxx17_uninitialized_value_construct_n(ForwardIt first, size_t n) {
-  using T = typename std::iterator_traits<ForwardIt>::value_type;
-  while (n > 0) {
-    new (std::addressof(*first)) T();
-    first++;
-    n--;
-  }
-  return first;
-}
-
-template <typename InputIt, typename OutputIt>
-InputIt cxx17_uninitialized_move(InputIt first, InputIt last, OutputIt out) {
-  using OutputT = typename std::iterator_traits<OutputIt>::value_type;
-  for (; first != last; ++first) {
-    new (std::addressof(*out)) OutputT(std::move(*first));
-    ++out;
-  }
-  return out;
-}
-
-template <typename ForwardIt>
-ForwardIt cxx17_destroy_n(ForwardIt first, size_t n) {
-  using T = typename std::iterator_traits<ForwardIt>::value_type;
-  while (n > 0) {
-    first->~T();
-    first++;
-    n--;
-  }
-  return first;
-}
-
 // New behaves like |new| but uses |OPENSSL_malloc| for memory allocation. It
 // returns nullptr on allocation error. It only implements single-object
 // allocation and not new T[n].
@@ -318,7 +271,7 @@
   // Reset releases the current contents of the array and takes ownership of the
   // raw pointer supplied by the caller.
   void Reset(T *new_data, size_t new_size) {
-    cxx17_destroy_n(data_, size_);
+    std::destroy_n(data_, size_);
     OPENSSL_free(data_);
     data_ = new_data;
     size_ = new_size;
@@ -341,7 +294,7 @@
     if (!InitUninitialized(new_size)) {
       return false;
     }
-    cxx17_uninitialized_value_construct_n(data_, size_);
+    std::uninitialized_value_construct_n(data_, size_);
     return true;
   }
 
@@ -352,7 +305,7 @@
     if (!InitUninitialized(new_size)) {
       return false;
     }
-    cxx17_uninitialized_default_construct_n(data_, size_);
+    std::uninitialized_default_construct_n(data_, size_);
     return true;
   }
 
@@ -372,7 +325,7 @@
     if (new_size > size_) {
       abort();
     }
-    cxx17_destroy_n(data_ + new_size, size_ - new_size);
+    std::destroy_n(data_ + new_size, size_ - new_size);
     size_ = new_size;
   }
 
@@ -440,7 +393,7 @@
   const T *end() const { return data_ + size_; }
 
   void clear() {
-    cxx17_destroy_n(data_, size_);
+    std::destroy_n(data_, size_);
     OPENSSL_free(data_);
     data_ = nullptr;
     size_ = 0;
@@ -499,7 +452,7 @@
       return false;
     }
     size_t new_size = size_;
-    cxx17_uninitialized_move(begin(), end(), new_data);
+    std::uninitialized_move(begin(), end(), new_data);
     clear();
     data_ = new_data;
     size_ = new_size;
@@ -543,7 +496,7 @@
   }
   InplaceVector &operator=(InplaceVector &&other) {
     clear();
-    cxx17_uninitialized_move(other.begin(), other.end(), data());
+    std::uninitialized_move(other.begin(), other.end(), data());
     size_ = other.size();
     return *this;
   }
@@ -575,7 +528,7 @@
   // default-constructible.
   void Shrink(size_t new_size) {
     BSSL_CHECK(new_size <= size_);
-    cxx17_destroy_n(data() + new_size, size_ - new_size);
+    std::destroy_n(data() + new_size, size_ - new_size);
     size_ = static_cast<PackedSize<N>>(new_size);
   }
 
@@ -590,7 +543,7 @@
     if (new_size > capacity()) {
       return false;
     }
-    cxx17_uninitialized_value_construct_n(data() + size_, new_size - size_);
+    std::uninitialized_value_construct_n(data() + size_, new_size - size_);
     size_ = static_cast<PackedSize<N>>(new_size);
     return true;
   }
@@ -606,7 +559,7 @@
     if (new_size > capacity()) {
       return false;
     }
-    cxx17_uninitialized_default_construct_n(data() + size_, new_size - size_);
+    std::uninitialized_default_construct_n(data() + size_, new_size - size_);
     size_ = static_cast<PackedSize<N>>(new_size);
     return true;
   }