Try to require C++14.

Now that we've dropped MSVC 2015, I believe we can rely on C++14 (which
is now seven years old). This switches the build to require C++14. I've
gone ahead and switched code in both public headers and within the
library, but if the public headers are a problem, we can revert those
separately.

C++14 doesn't get us quite as much as C++17, but see if we can get to
C++14 first. Still, std::enable_if_t and the less restricted constexpr
are nice wins.

Update-Note: C++14 is now required to build BoringSSL. If the build
breaks, make sure your compiler is C++14-capable and is not passing
-std=c++11. If this is causing problems for your project, let us know.

Change-Id: If03a88e3f8a11980180781f95b806e7f3c3cb6c3
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/52246
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
fips-20220613
David Benjamin 3 years ago committed by Boringssl LUCI CQ
parent edbdc240ec
commit 493d5cbedd
  1. 2
      BUILDING.md
  2. 2
      CMakeLists.txt
  3. 6
      crypto/test/abi_test.h
  4. 17
      include/openssl/span.h
  5. 17
      include/openssl/stack.h
  6. 2
      ssl/internal.h
  7. 45
      ssl/ssl_cipher.cc
  8. 4
      util/BUILD.toplevel
  9. 2
      util/generate_build_files.py

@ -30,7 +30,7 @@ most recent stable version of each tool.
by CMake, it may be configured explicitly by setting by CMake, it may be configured explicitly by setting
`CMAKE_ASM_NASM_COMPILER`. `CMAKE_ASM_NASM_COMPILER`.
* C and C++ compilers with C++11 support are required. On Windows, MSVC from * C and C++ compilers with C++14 support are required. On Windows, MSVC from
Visual Studio 2017 or later with Platform SDK 8.1 or later are supported, Visual Studio 2017 or later with Platform SDK 8.1 or later are supported,
but newer versions are recommended. Recent versions of GCC (6.1+) and Clang but newer versions are recommended. Recent versions of GCC (6.1+) and Clang
should work on non-Windows platforms, and maybe on Windows too. should work on non-Windows platforms, and maybe on Windows too.

@ -163,7 +163,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_CXX_FLAGS} -Wmissing-declarations") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_CXX_FLAGS} -Wmissing-declarations")
if(NOT MSVC) if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
if(APPLE) if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif() endif()

@ -380,9 +380,9 @@ inline crypto_word_t CheckImpl(Result *out, bool unwind, R (*func)(Args...),
// CheckImpl implementation. It must be specialized for void returns because we // CheckImpl implementation. It must be specialized for void returns because we
// call |func| directly. // call |func| directly.
template <typename R, typename... Args> template <typename R, typename... Args>
inline typename std::enable_if<!std::is_void<R>::value, crypto_word_t>::type inline std::enable_if_t<!std::is_void<R>::value, crypto_word_t> CheckImpl(
CheckImpl(Result *out, bool /* unwind */, R (*func)(Args...), Result *out, bool /* unwind */, R (*func)(Args...),
typename DeductionGuard<Args>::Type... args) { typename DeductionGuard<Args>::Type... args) {
*out = Result(); *out = Result();
return func(args...); return func(args...);
} }

@ -99,12 +99,11 @@ class Span : private internal::SpanBase<const T> {
// Heuristically test whether C is a container type that can be converted into // Heuristically test whether C is a container type that can be converted into
// a Span by checking for data() and size() member functions. // a Span by checking for data() and size() member functions.
// //
// TODO(davidben): Require C++14 support and switch to std::enable_if_t. // TODO(davidben): Require C++17 support for std::is_convertible_v, etc.
// Perhaps even C++17 now?
template <typename C> template <typename C>
using EnableIfContainer = typename std::enable_if< using EnableIfContainer = std::enable_if_t<
std::is_convertible<decltype(std::declval<C>().data()), T *>::value && std::is_convertible<decltype(std::declval<C>().data()), T *>::value &&
std::is_integral<decltype(std::declval<C>().size())>::value>::type; std::is_integral<decltype(std::declval<C>().size())>::value>;
public: public:
constexpr Span() : Span(nullptr, 0) {} constexpr Span() : Span(nullptr, 0) {}
@ -113,14 +112,12 @@ class Span : private internal::SpanBase<const T> {
template <size_t N> template <size_t N>
constexpr Span(T (&array)[N]) : Span(array, N) {} constexpr Span(T (&array)[N]) : Span(array, N) {}
template < template <typename C, typename = EnableIfContainer<C>,
typename C, typename = EnableIfContainer<C>, typename = std::enable_if_t<std::is_const<T>::value, C>>
typename = typename std::enable_if<std::is_const<T>::value, C>::type>
Span(const C &container) : data_(container.data()), size_(container.size()) {} Span(const C &container) : data_(container.data()), size_(container.size()) {}
template < template <typename C, typename = EnableIfContainer<C>,
typename C, typename = EnableIfContainer<C>, typename = std::enable_if_t<!std::is_const<T>::value, C>>
typename = typename std::enable_if<!std::is_const<T>::value, C>::type>
explicit Span(C &container) explicit Span(C &container)
: data_(container.data()), size_(container.size()) {} : data_(container.data()), size_(container.size()) {}

@ -443,16 +443,14 @@ namespace internal {
// Stacks defined with |DEFINE_CONST_STACK_OF| are freed with |sk_free|. // Stacks defined with |DEFINE_CONST_STACK_OF| are freed with |sk_free|.
template <typename Stack> template <typename Stack>
struct DeleterImpl< struct DeleterImpl<Stack, std::enable_if_t<StackTraits<Stack>::kIsConst>> {
Stack, typename std::enable_if<StackTraits<Stack>::kIsConst>::type> {
static void Free(Stack *sk) { sk_free(reinterpret_cast<_STACK *>(sk)); } static void Free(Stack *sk) { sk_free(reinterpret_cast<_STACK *>(sk)); }
}; };
// Stacks defined with |DEFINE_STACK_OF| are freed with |sk_pop_free| and the // Stacks defined with |DEFINE_STACK_OF| are freed with |sk_pop_free| and the
// corresponding type's deleter. // corresponding type's deleter.
template <typename Stack> template <typename Stack>
struct DeleterImpl< struct DeleterImpl<Stack, std::enable_if_t<!StackTraits<Stack>::kIsConst>> {
Stack, typename std::enable_if<!StackTraits<Stack>::kIsConst>::type> {
static void Free(Stack *sk) { static void Free(Stack *sk) {
// sk_FOO_pop_free is defined by macros and bound by name, so we cannot // sk_FOO_pop_free is defined by macros and bound by name, so we cannot
// access it from C++ here. // access it from C++ here.
@ -502,18 +500,17 @@ class StackIteratorImpl {
}; };
template <typename Stack> template <typename Stack>
using StackIterator = typename std::enable_if<StackTraits<Stack>::kIsStack, using StackIterator =
StackIteratorImpl<Stack>>::type; std::enable_if_t<StackTraits<Stack>::kIsStack, StackIteratorImpl<Stack>>;
} // namespace internal } // namespace internal
// PushToStack pushes |elem| to |sk|. It returns true on success and false on // PushToStack pushes |elem| to |sk|. It returns true on success and false on
// allocation failure. // allocation failure.
template <typename Stack> template <typename Stack>
inline inline std::enable_if_t<!internal::StackTraits<Stack>::kIsConst, bool>
typename std::enable_if<!internal::StackTraits<Stack>::kIsConst, bool>::type PushToStack(Stack *sk,
PushToStack(Stack *sk, UniquePtr<typename internal::StackTraits<Stack>::Type> elem) {
UniquePtr<typename internal::StackTraits<Stack>::Type> elem) {
if (!sk_push(reinterpret_cast<_STACK *>(sk), elem.get())) { if (!sk_push(reinterpret_cast<_STACK *>(sk), elem.get())) {
return false; return false;
} }

@ -216,7 +216,7 @@ void Delete(T *t) {
// may be C structs which require a |BORINGSSL_MAKE_DELETER| registration. // may be C structs which require a |BORINGSSL_MAKE_DELETER| registration.
namespace internal { namespace internal {
template <typename T> template <typename T>
struct DeleterImpl<T, typename std::enable_if<T::kAllowUniquePtr>::type> { struct DeleterImpl<T, std::enable_if_t<T::kAllowUniquePtr>> {
static void Free(T *t) { Delete(t); } static void Free(T *t) { Delete(t); }
}; };
} // namespace internal } // namespace internal

@ -1327,34 +1327,33 @@ BSSL_NAMESPACE_END
using namespace bssl; using namespace bssl;
static constexpr int ssl_cipher_id_cmp_inner(const SSL_CIPHER *a, static constexpr int ssl_cipher_id_cmp(const SSL_CIPHER *a,
const SSL_CIPHER *b) { const SSL_CIPHER *b) {
// C++11's constexpr functions must have a body consisting of just a if (a->id > b->id) {
// return-statement. return 1;
return (a->id > b->id) ? 1 : ((a->id < b->id) ? -1 : 0); }
} if (a->id < b->id) {
return -1;
static int ssl_cipher_id_cmp(const void *in_a, const void *in_b) { }
return ssl_cipher_id_cmp_inner(reinterpret_cast<const SSL_CIPHER *>(in_a), return 0;
reinterpret_cast<const SSL_CIPHER *>(in_b));
} }
template <typename T, size_t N> static int ssl_cipher_id_cmp_void(const void *in_a, const void *in_b) {
static constexpr size_t countof(T const (&)[N]) { return ssl_cipher_id_cmp(reinterpret_cast<const SSL_CIPHER *>(in_a),
return N; reinterpret_cast<const SSL_CIPHER *>(in_b));
} }
template <typename T, size_t I> template <size_t N>
static constexpr int check_order(const T (&arr)[I], size_t N) { static constexpr bool ssl_ciphers_sorted(const SSL_CIPHER (&ciphers)[N]) {
// C++11's constexpr functions must have a body consisting of just a for (size_t i = 1; i < N; i++) {
// return-statement. if (ssl_cipher_id_cmp(&ciphers[i - 1], &ciphers[i]) >= 0) {
return N > 1 ? ((ssl_cipher_id_cmp_inner(&arr[N - 2], &arr[N - 1]) < 0) return false;
? check_order(arr, N - 1) }
: 0) }
: 1; return true;
} }
static_assert(check_order(kCiphers, countof(kCiphers)) == 1, static_assert(ssl_ciphers_sorted(kCiphers),
"Ciphers are not sorted, bsearch won't work"); "Ciphers are not sorted, bsearch won't work");
const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) { const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) {
@ -1363,7 +1362,7 @@ const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) {
c.id = 0x03000000L | value; c.id = 0x03000000L | value;
return reinterpret_cast<const SSL_CIPHER *>(bsearch( return reinterpret_cast<const SSL_CIPHER *>(bsearch(
&c, kCiphers, OPENSSL_ARRAY_SIZE(kCiphers), sizeof(SSL_CIPHER), &c, kCiphers, OPENSSL_ARRAY_SIZE(kCiphers), sizeof(SSL_CIPHER),
ssl_cipher_id_cmp)); ssl_cipher_id_cmp_void));
} }
uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher) { return cipher->id; } uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher) { return cipher->id; }

@ -137,9 +137,9 @@ boringssl_copts_c11 = boringssl_copts + select({
"//conditions:default": [], "//conditions:default": [],
}) })
# For C++ targets only (not C), compile with C++11 support. # For C++ targets only (not C), compile with C++14 support.
posix_copts_cxx = [ posix_copts_cxx = [
"-std=c++11", "-std=c++14",
"-Wmissing-declarations", "-Wmissing-declarations",
] ]

@ -437,7 +437,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
endif() endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CLANG) if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fvisibility=hidden -fno-common -fno-exceptions -fno-rtti") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fvisibility=hidden -fno-common -fno-exceptions -fno-rtti")
if(APPLE) if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif() endif()

Loading…
Cancel
Save