Add feature tests for C++20 constexpr and consteval
This restores support for building pw_rpc with xtensa-esp32-elf-gcc
(crosstool-NG esp-2020r3) 8.4.0.
No-Docs-Update-Reason: bug fix
Change-Id: Ia8af09844855f130e866c2c42f18230da7962118
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/48701
Commit-Queue: Michael Spang <spang@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
diff --git a/pw_bytes/public/pw_bytes/array.h b/pw_bytes/public/pw_bytes/array.h
index 453f9ea..5b81229 100644
--- a/pw_bytes/public/pw_bytes/array.h
+++ b/pw_bytes/public/pw_bytes/array.h
@@ -20,6 +20,8 @@
#include <cstddef>
#include <iterator>
+#include "pw_polyfill/language_feature_macros.h"
+
namespace pw::bytes {
namespace internal {
@@ -30,7 +32,7 @@
// byte-sized elements or the underlying bytes of an integer (as little-endian).
// std::memcpy cannot be used since it is not constexpr.
template <typename B, typename T, typename... Args>
-consteval void CopyBytes(B* array, T value, Args... args) {
+PW_CONSTEVAL void CopyBytes(B* array, T value, Args... args) {
static_assert(sizeof(B) == sizeof(std::byte));
if constexpr (UseBytesDirectly<T>) {
@@ -56,7 +58,7 @@
// Evaluates to the size in bytes of an integer or byte array.
template <typename T>
-consteval size_t SizeOfBytes(const T& arg) {
+PW_CONSTEVAL size_t SizeOfBytes(const T& arg) {
if constexpr (UseBytesDirectly<T>) {
return sizeof(arg);
} else {
@@ -66,12 +68,12 @@
}
template <typename B, typename T, size_t... kIndex>
-consteval auto String(const T& array, std::index_sequence<kIndex...>) {
+PW_CONSTEVAL auto String(const T& array, std::index_sequence<kIndex...>) {
return std::array{static_cast<B>(array[kIndex])...};
}
template <typename T, typename U>
-consteval bool CanBeRepresentedAsByteType(const U& value) {
+PW_CONSTEVAL bool CanBeRepresentedAsByteType(const U& value) {
return static_cast<U>(static_cast<T>(value)) == value;
}
@@ -80,7 +82,7 @@
// Concatenates arrays or integers as a byte array at compile time. Integer
// values are copied little-endian. Spans are copied byte-for-byte.
template <typename B = std::byte, typename... Args>
-consteval auto Concat(Args... args) {
+PW_CONSTEVAL auto Concat(Args... args) {
std::array<B, (internal::SizeOfBytes(args) + ...)> bytes{};
internal::CopyBytes(bytes.begin(), args...);
return bytes;
@@ -90,27 +92,27 @@
template <typename B = std::byte,
size_t kSize,
typename Indices = std::make_index_sequence<kSize - 1>>
-consteval auto String(const char (&str)[kSize]) {
+PW_CONSTEVAL auto String(const char (&str)[kSize]) {
return internal::String<B>(str, Indices{});
}
// String overload for the empty string "".
template <typename B = std::byte>
-consteval auto String(const char (&)[1]) {
+PW_CONSTEVAL auto String(const char (&)[1]) {
return std::array<B, 0>{};
}
// Creates an array of bytes from values passed as template parameters. The
// values are guaranteed to be representable in the destination byte type.
template <typename B, auto... values>
-consteval auto Array() {
+PW_CONSTEVAL auto Array() {
static_assert((internal::CanBeRepresentedAsByteType<B>(values) && ...));
return std::array<B, sizeof...(values)>{static_cast<B>(values)...};
}
// Array() defaults to using std::byte.
template <auto... values>
-consteval auto Array() {
+PW_CONSTEVAL auto Array() {
return Array<std::byte, values...>();
}
diff --git a/pw_polyfill/public/pw_polyfill/language_feature_macros.h b/pw_polyfill/public/pw_polyfill/language_feature_macros.h
index 389493f..60f290c 100644
--- a/pw_polyfill/public/pw_polyfill/language_feature_macros.h
+++ b/pw_polyfill/public/pw_polyfill/language_feature_macros.h
@@ -29,3 +29,17 @@
#else
#define PW_CONSTEXPR_FUNCTION
#endif // __cpp_constexpr >= 201304L
+
+// Mark functions as constexpr if C++20 or newer
+#if __cplusplus >= 202002L
+#define PW_CONSTEXPR_CPP20 constexpr
+#else
+#define PW_CONSTEXPR_CPP20
+#endif // __cpp_constexpr >= 201304L
+
+// Mark functions as consteval if supported.
+#if defined(__cpp_consteval) && __cpp_consteval >= 201811L
+#define PW_CONSTEVAL consteval
+#else
+#define PW_CONSTEVAL PW_CONSTEXPR_FUNCTION
+#endif // __cpp_consteval >= 201811L
diff --git a/pw_string/public/pw_string/util.h b/pw_string/public/pw_string/util.h
index 6b58308..0b81867 100644
--- a/pw_string/public/pw_string/util.h
+++ b/pw_string/public/pw_string/util.h
@@ -73,8 +73,8 @@
//
// Precondition: The destination and source shall not overlap.
// Precondition: The source shall be a valid pointer.
-constexpr StatusWithSize Copy(const std::string_view& source,
- std::span<char> dest) {
+PW_CONSTEXPR_CPP20 inline StatusWithSize Copy(const std::string_view& source,
+ std::span<char> dest) {
if (dest.empty()) {
return StatusWithSize::ResourceExhausted();
}
@@ -87,12 +87,15 @@
copied);
}
-constexpr StatusWithSize Copy(const char* source, std::span<char> dest) {
+PW_CONSTEXPR_CPP20 inline StatusWithSize Copy(const char* source,
+ std::span<char> dest) {
PW_DASSERT(source != nullptr);
return Copy(ClampedCString(source, dest.size()), dest);
}
-constexpr StatusWithSize Copy(const char* source, char* dest, size_t num) {
+PW_CONSTEXPR_CPP20 inline StatusWithSize Copy(const char* source,
+ char* dest,
+ size_t num) {
return Copy(source, std::span<char>(dest, num));
}