diff --git a/docs/index.rst b/docs/index.rst index 33a7fbf0dd..1abb6f4f79 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -149,7 +149,7 @@ Here is a selection of interesting modules: - :ref:`module-pw_polyfill` - Similar to JavaScript “polyfill” libraries, this module provides selected C++17 standard library components that are - compatible with C++11 and C++14. + compatible with C++14. - :ref:`module-pw_tokenizer` - Replace string literals from log statements with 32-bit tokens, to reduce flash use, reduce logging bandwidth, and save diff --git a/docs/style_guide.rst b/docs/style_guide.rst index 933f17329d..5d90719572 100644 --- a/docs/style_guide.rst +++ b/docs/style_guide.rst @@ -13,7 +13,6 @@ Style Guide and Conventions --------- C++ style --------- - The Pigweed C++ style guide is closely based on Google's external C++ Style Guide, which is found on the web at https://google.github.io/styleguide/cppguide.html. The Google C++ Style Guide @@ -28,6 +27,20 @@ Recommendations in the :doc:`embedded_cpp_guide` are considered part of the Pigweed style guide, but are separated out since it covers more general embedded development beyond just C++ style. +C++ standard +============ +Pigweed primarily uses the C++17 standard. A few modules maintain support for +C++14, however (e.g. :ref:`module-pw_kvs` and its dependencies). + +All Pigweed C++ code must compile with ``-std=C++17`` in Clang and GCC. C++20 +features may be used as long as the code still compiles unmodified with C++17. +See ``pw_polyfill/language_feature_macros.h`` for macros that provide C++20 +features when supported. + +Compiler extensions should not be used unless wrapped in a macro or properly +guarded in the preprocessor. See ``pw_processor/compiler.h`` for macros that +wrap compiler-specific features. + Automatic formatting ==================== Pigweed uses `clang-format `_ to diff --git a/docs/targets.rst b/docs/targets.rst index 160c1f9352..7c13097dc6 100644 --- a/docs/targets.rst +++ b/docs/targets.rst @@ -51,7 +51,7 @@ build argument defined in Pigweed. Some notable arguments include: * ``default_public_deps``: List of GN targets which are added as a dependency to all ``pw_*`` GN targets. This is used to add global module dependencies; for example, in upstream, ``pw_polyfill`` is added here to provide C++17 - features in C++11/C++14 code. + features in C++14 code. * Facade backends: Pigweed defines facades to provide a common interface for core system features such as logging without assuming an implementation. When building a Pigweed target, the implementations for each of these must be diff --git a/pw_build/BUILD.gn b/pw_build/BUILD.gn index 6e71c39149..41069a9ddc 100644 --- a/pw_build/BUILD.gn +++ b/pw_build/BUILD.gn @@ -105,10 +105,6 @@ config("extra_strict_warnings") { cflags_c = [ "-Wstrict-prototypes" ] } -config("cpp11") { - cflags_cc = [ "-std=c++11" ] -} - config("cpp14") { cflags_cc = [ "-std=c++14" ] } diff --git a/pw_polyfill/BUILD.gn b/pw_polyfill/BUILD.gn index d0339ac0a8..50e187da50 100644 --- a/pw_polyfill/BUILD.gn +++ b/pw_polyfill/BUILD.gn @@ -88,7 +88,6 @@ pw_source_set("standard_library") { pw_test_group("tests") { tests = [ ":default_cpp_test", - ":cpp11_test", ":cpp14_test", ] group_deps = [ "$dir_pw_span:tests" ] @@ -99,13 +98,6 @@ pw_test("default_cpp_test") { sources = [ "test.cc" ] } -pw_test("cpp11_test") { - remove_configs = [ "$dir_pw_build:cpp17" ] - configs = [ "$dir_pw_build:cpp11" ] - sources = [ "test.cc" ] - deps = [ ":pw_polyfill" ] -} - pw_test("cpp14_test") { remove_configs = [ "$dir_pw_build:cpp17" ] configs = [ "$dir_pw_build:cpp14" ] diff --git a/pw_polyfill/README.md b/pw_polyfill/README.md index 14128d7125..fa360fd0f2 100644 --- a/pw_polyfill/README.md +++ b/pw_polyfill/README.md @@ -1 +1 @@ -# pw\_polyfill: Backports C++17 features to C++11 and C++14 +# pw\_polyfill: Backports C++17 features to C++14 diff --git a/pw_polyfill/docs.rst b/pw_polyfill/docs.rst index a344b277ff..1f8f966b47 100644 --- a/pw_polyfill/docs.rst +++ b/pw_polyfill/docs.rst @@ -3,9 +3,7 @@ =========== pw_polyfill =========== -The ``pw_polyfill`` module backports new C++ features to older C++ standards. -When possible, features are adapted to work with in standards as old as C++11. -Pigweed does not support C++ standards older than C++11. +The ``pw_polyfill`` module backports new C++ features to C++14. ------------------------------------------------ Backport new C++ features to older C++ standards @@ -22,7 +20,7 @@ C headers. The wrapper headers include the original header using `#include_next `_, then add missing features. The backported features are only defined if they aren't provided by the standard header, so ``pw_polyfill`` is safe to use when -compiling with any standard C++11 or newer. +compiling with any standard C++14 or newer. Language features are backported or stubbed via the ``pw_polyfill/language_features.h`` header. This header is included in files @@ -39,17 +37,17 @@ for the ``language_features.h`` header. Backported features =================== -================== ================================ ============================================ ======================================== -Header Feature Level of support Feature test macro -================== ================================ ============================================ ======================================== - std::endian full __cpp_lib_endian - std::byte full; some operators not constexpr in C++11 __cpp_lib_byte - std::data, std::size full __cpp_lib_nonmember_container_access - \*_t trait aliases partial (can expand as needed) __cpp_lib_transformation_trait_aliases - std::is_null_pointer full __cpp_lib_is_null_pointer - std::integer_sequence & helpers full __cpp_lib_integer_sequence -(language feature) static_assert with no message full __cpp_static_assert -================== ================================ ============================================ ======================================== +================== ================================ =============================== ======================================== +Header Feature Level of support Feature test macro +================== ================================ =============================== ======================================== + std::endian full __cpp_lib_endian + std::byte full __cpp_lib_byte + std::data, std::size full __cpp_lib_nonmember_container_access + \*_t trait aliases partial (can expand as needed) __cpp_lib_transformation_trait_aliases + std::is_null_pointer full __cpp_lib_is_null_pointer + std::integer_sequence & helpers full __cpp_lib_integer_sequence +(language feature) static_assert with no message full __cpp_static_assert +================== ================================ =============================== ======================================== ---------------------------------------------------- Adapt code to compile with different versions of C++ @@ -67,7 +65,6 @@ Language feature macros Macro Feature Description Feature test macro ====================== ================================ ======================================== ========================== PW_INLINE_VARIABLE inline variables inline if supported by the compiler __cpp_inline_variables -PW_CONSTEXPR_FUNCTION relaxed constexpr function rules constexpr if relaxed rules are supported __cpp_constexpr >= 201304L PW_CONSTEXPR_CPP20 constexpr in C++20 constexpr if compiling for C++20 __cplusplus >= 202002L PW_CONSTEVAL consteval consteval if supported by the compiler __cpp_consteval PW_CONSTINIT constinit constinit in clang and GCC 10+ __cpp_constinit @@ -81,4 +78,4 @@ systems, add ``pw_polyfill/standard_library_public`` and ------------- Compatibility ------------- -C++11 +C++14 diff --git a/pw_polyfill/public/pw_polyfill/language_feature_macros.h b/pw_polyfill/public/pw_polyfill/language_feature_macros.h index 4dae50332c..1a4caa6977 100644 --- a/pw_polyfill/public/pw_polyfill/language_feature_macros.h +++ b/pw_polyfill/public/pw_polyfill/language_feature_macros.h @@ -23,13 +23,6 @@ #define PW_INLINE_VARIABLE #endif // __cpp_inline_variables -// Mark functions as constexpr if the relaxed constexpr rules are supported. -#if __cpp_constexpr >= 201304L -#define PW_CONSTEXPR_FUNCTION constexpr -#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 diff --git a/pw_polyfill/standard_library_public/pw_polyfill/standard_library/cstddef.h b/pw_polyfill/standard_library_public/pw_polyfill/standard_library/cstddef.h index 763224ca07..cc97310950 100644 --- a/pw_polyfill/standard_library_public/pw_polyfill/standard_library/cstddef.h +++ b/pw_polyfill/standard_library_public/pw_polyfill/standard_library/cstddef.h @@ -56,20 +56,10 @@ constexpr byte operator>>(byte b, I shift) noexcept { return byte(static_cast(b) >> shift); } -#if __cpp_constexpr >= 201304L - constexpr byte& operator|=(byte& l, byte r) noexcept { return l = l | r; } constexpr byte& operator&=(byte& l, byte r) noexcept { return l = l & r; } constexpr byte& operator^=(byte& l, byte r) noexcept { return l = l ^ r; } -#else // For C++11 compatiblity, these operators cannot be constexpr. - -inline byte& operator|=(byte& l, byte r) noexcept { return l = l | r; } -inline byte& operator&=(byte& l, byte r) noexcept { return l = l & r; } -inline byte& operator^=(byte& l, byte r) noexcept { return l = l ^ r; } - -#endif // __cpp_constexpr >= 201304L - template inline byte& operator<<=(byte& b, I shift) noexcept { return b = b << shift; diff --git a/pw_polyfill/test.cc b/pw_polyfill/test.cc index 2646ebf994..9b257b9f98 100644 --- a/pw_polyfill/test.cc +++ b/pw_polyfill/test.cc @@ -33,12 +33,7 @@ static_assert(foo == 42, "Error!"); static_assert(PW_CXX_STANDARD_IS_SUPPORTED(98), "C++98 must be supported"); static_assert(PW_CXX_STANDARD_IS_SUPPORTED(11), "C++11 must be supported"); - -#if __cplusplus >= 201402L -static_assert(PW_CXX_STANDARD_IS_SUPPORTED(14), "C++14 must be not supported"); -#else -static_assert(!PW_CXX_STANDARD_IS_SUPPORTED(14), "C++14 must be supported"); -#endif // __cplusplus >= 201402L +static_assert(PW_CXX_STANDARD_IS_SUPPORTED(14), "C++14 must be supported"); #if __cplusplus >= 201703L static_assert(PW_CXX_STANDARD_IS_SUPPORTED(17), "C++17 must be not supported"); @@ -48,9 +43,9 @@ static_assert(!PW_CXX_STANDARD_IS_SUPPORTED(17), "C++17 must be supported"); TEST(Bit, Endian) { if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) { - EXPECT_TRUE(std::endian::native == std::endian::big); + EXPECT_EQ(std::endian::native, std::endian::big); } else if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) { - EXPECT_TRUE(std::endian::native == std::endian::little); + EXPECT_EQ(std::endian::native, std::endian::little); } else { FAIL(); } @@ -58,21 +53,21 @@ TEST(Bit, Endian) { TEST(Cstddef, Byte_Operators) { std::byte value = std::byte(0); - EXPECT_TRUE((value | std::byte(0x12)) == std::byte(0x12)); - EXPECT_TRUE((value & std::byte(0x12)) == std::byte(0)); - EXPECT_TRUE((value ^ std::byte(0x12)) == std::byte(0x12)); - EXPECT_TRUE(~std::byte(0) == std::byte(-1)); - EXPECT_TRUE((std::byte(1) << 3) == std::byte(0x8)); - EXPECT_TRUE((std::byte(0x8) >> 3) == std::byte(1)); + EXPECT_EQ((value | std::byte(0x12)), std::byte(0x12)); + EXPECT_EQ((value & std::byte(0x12)), std::byte(0)); + EXPECT_EQ((value ^ std::byte(0x12)), std::byte(0x12)); + EXPECT_EQ(~std::byte(0), std::byte(-1)); + EXPECT_EQ((std::byte(1) << 3), std::byte(0x8)); + EXPECT_EQ((std::byte(0x8) >> 3), std::byte(1)); } TEST(Cstddef, Byte_AssignmentOperators) { std::byte value = std::byte(0); - EXPECT_TRUE((value |= std::byte(0x12)) == std::byte(0x12)); - EXPECT_TRUE((value &= std::byte(0x0F)) == std::byte(0x02)); - EXPECT_TRUE((value ^= std::byte(0xFF)) == std::byte(0xFD)); - EXPECT_TRUE((value <<= 4) == std::byte(0xD0)); - EXPECT_TRUE((value >>= 5) == std::byte(0x6)); + EXPECT_EQ((value |= std::byte(0x12)), std::byte(0x12)); + EXPECT_EQ((value &= std::byte(0x0F)), std::byte(0x02)); + EXPECT_EQ((value ^= std::byte(0xFF)), std::byte(0xFD)); + EXPECT_EQ((value <<= 4), std::byte(0xD0)); + EXPECT_EQ((value >>= 5), std::byte(0x6)); } // Check that consteval is at least equivalent to constexpr. @@ -83,13 +78,13 @@ int c_array[5423] = {}; std::array array; TEST(Iterator, Size) { - EXPECT_TRUE(std::size(c_array) == sizeof(c_array) / sizeof(*c_array)); - EXPECT_TRUE(std::size(array) == array.size()); + EXPECT_EQ(std::size(c_array), sizeof(c_array) / sizeof(*c_array)); + EXPECT_EQ(std::size(array), array.size()); } TEST(Iterator, Data) { - EXPECT_TRUE(std::data(c_array) == c_array); - EXPECT_TRUE(std::data(array) == array.data()); + EXPECT_EQ(std::data(c_array), c_array); + EXPECT_EQ(std::data(array), array.data()); } PW_CONSTINIT bool mutable_value = true; diff --git a/pw_result/docs.rst b/pw_result/docs.rst index 02c94757f3..57d1610831 100644 --- a/pw_result/docs.rst +++ b/pw_result/docs.rst @@ -78,7 +78,7 @@ similar type. Compatibility ============= -Works with C++11, but some features require C++17. +Works with C++14, but some features require C++17. Size report =========== diff --git a/pw_ring_buffer/docs.rst b/pw_ring_buffer/docs.rst index 986a82c8c3..a0efbfec4c 100644 --- a/pw_ring_buffer/docs.rst +++ b/pw_ring_buffer/docs.rst @@ -10,7 +10,7 @@ This documentation is incomplete :) Compatibility ============= -* C++11 +* C++14 Iterator ======== diff --git a/pw_span/docs.rst b/pw_span/docs.rst index 2987ce4491..c1bfcd0bc2 100644 --- a/pw_span/docs.rst +++ b/pw_span/docs.rst @@ -68,4 +68,4 @@ Pointer and size arguments can be replaced with a ``std::span``: Compatibility ============= -Works with C++11, but some features require C++17. +Works with C++14, but some features require C++17. diff --git a/pw_span/public/pw_span/internal/span.h b/pw_span/public/pw_span/internal/span.h index d6b6a418cb..4e37611a41 100644 --- a/pw_span/public/pw_span/internal/span.h +++ b/pw_span/public/pw_span/internal/span.h @@ -320,7 +320,7 @@ class span : public pw_span_internal::ExtentStorage { constexpr span(const span& other) : span(other.data(), other.size()) {} - PW_CONSTEXPR_FUNCTION span& operator=(const span& other) noexcept = default; + constexpr span& operator=(const span& other) noexcept = default; ~span() noexcept = default; // [span.sub], span subviews diff --git a/pw_status/docs.rst b/pw_status/docs.rst index 1a5790f37a..3830d7a604 100644 --- a/pw_status/docs.rst +++ b/pw_status/docs.rst @@ -292,4 +292,4 @@ the size from the StatusWithSize on ok. Compatibility ============= -C++11 +C++14 diff --git a/pw_tokenizer/BUILD.gn b/pw_tokenizer/BUILD.gn index fe93aa3387..d5a4fa320f 100644 --- a/pw_tokenizer/BUILD.gn +++ b/pw_tokenizer/BUILD.gn @@ -194,7 +194,6 @@ pw_test_group("tests") { ":detokenize_test", ":global_handlers_test", ":hash_test", - ":simple_tokenize_test_cpp11", ":simple_tokenize_test_cpp14", ":simple_tokenize_test_cpp17", ":token_database_fuzzer", @@ -270,8 +269,7 @@ pw_test("hash_test") { deps = [ ":pw_tokenizer" ] } -# Fully test C++11 and C++14 compatibility by compiling all sources as C++11 or -# C++14. +# Fully test C++14 compatibility by compiling all sources as C++14. _simple_tokenize_test_sources = [ "$dir_pw_containers/public/pw_containers/to_array.h", "$dir_pw_varint/public/pw_varint/varint.h", @@ -301,13 +299,6 @@ _simple_tokenize_test_configs = [ "$dir_pw_containers:public_include_path", ] -pw_test("simple_tokenize_test_cpp11") { - remove_configs = [ "$dir_pw_build:cpp17" ] - configs = [ "$dir_pw_build:cpp11" ] + _simple_tokenize_test_configs - sources = _simple_tokenize_test_sources - deps = [ dir_pw_preprocessor ] -} - pw_test("simple_tokenize_test_cpp14") { remove_configs = [ "$dir_pw_build:cpp17" ] configs = [ "$dir_pw_build:cpp14" ] + _simple_tokenize_test_configs diff --git a/pw_tokenizer/docs.rst b/pw_tokenizer/docs.rst index 5c06c3081f..78f8e74c57 100644 --- a/pw_tokenizer/docs.rst +++ b/pw_tokenizer/docs.rst @@ -1144,7 +1144,7 @@ The Python tooling continues to support the legacy tokenized string ELF format. Compatibility ============= * C11 - * C++11 + * C++14 * Python 3 Dependencies diff --git a/pw_tokenizer/public/pw_tokenizer/internal/argument_types.h b/pw_tokenizer/public/pw_tokenizer/internal/argument_types.h index 79f631d99d..0fdf96bc5f 100644 --- a/pw_tokenizer/public/pw_tokenizer/internal/argument_types.h +++ b/pw_tokenizer/public/pw_tokenizer/internal/argument_types.h @@ -105,7 +105,7 @@ constexpr pw_tokenizer_ArgTypes VarargsType() { } } -#else // C++11 or C++14 version +#else // C++14 version template (), diff --git a/pw_tokenizer/simple_tokenize_test.cc b/pw_tokenizer/simple_tokenize_test.cc index 4112cef381..79313e8212 100644 --- a/pw_tokenizer/simple_tokenize_test.cc +++ b/pw_tokenizer/simple_tokenize_test.cc @@ -51,18 +51,18 @@ uint32_t TestHash(const char (&str)[kSize]) TEST(TokenizeStringLiteral, EmptyString_IsZero) { constexpr pw_tokenizer_Token token = PW_TOKENIZE_STRING(""); - EXPECT_TRUE(0u == token); + EXPECT_EQ(0u, token); } TEST(TokenizeStringLiteral, String_MatchesHash) { constexpr uint32_t token = PW_TOKENIZE_STRING("[:-)"); - EXPECT_TRUE(TestHash("[:-)") == token); + EXPECT_EQ(TestHash("[:-)"), token); } constexpr uint32_t kGlobalToken = PW_TOKENIZE_STRING(">:-[]"); TEST(TokenizeStringLiteral, GlobalVariable_MatchesHash) { - EXPECT_TRUE(TestHash(">:-[]") == kGlobalToken); + EXPECT_EQ(TestHash(">:-[]"), kGlobalToken); } class TokenizeToBuffer : public ::testing::Test { @@ -80,7 +80,7 @@ template class GlobalMessage : public ::testing::Test { public: static void SetMessage(const uint8_t* message, size_t size) { - ASSERT_TRUE(size <= sizeof(message_)); + ASSERT_LE(size, sizeof(message_)); std::memcpy(message_, message, size); message_size_bytes_ = size; } @@ -124,8 +124,8 @@ TEST_F(TokenizeToCallback, Variety) { 0x5C // char '.' (0x2E, zig-zag encoded) >("%s there are %x (%.2f) of them%c"); // clang-format on - ASSERT_TRUE(expected.size() == message_size_bytes_); - EXPECT_TRUE(std::memcmp(expected.data(), message_, expected.size()) == 0); + ASSERT_EQ(expected.size(), message_size_bytes_); + EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0); } class TokenizeToGlobalHandler : public GlobalMessage { @@ -135,8 +135,8 @@ TEST_F(TokenizeToGlobalHandler, Variety) { PW_TOKENIZE_TO_GLOBAL_HANDLER("%x%lld%1.2f%s", 0, 0ll, -0.0, ""); const auto expected = ExpectedData<0, 0, 0x00, 0x00, 0x00, 0x80, 0>("%x%lld%1.2f%s"); - ASSERT_TRUE(expected.size() == message_size_bytes_); - EXPECT_TRUE(std::memcmp(expected.data(), message_, expected.size()) == 0); + ASSERT_EQ(expected.size(), message_size_bytes_); + EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0); } extern "C" void pw_tokenizer_HandleEncodedMessage( @@ -160,7 +160,7 @@ class TokenizeToGlobalHandlerWithPayload intptr_t TokenizeToGlobalHandlerWithPayload::payload_; TEST_F(TokenizeToGlobalHandlerWithPayload, Variety) { - ASSERT_TRUE(payload_ != 123); + ASSERT_NE(payload_, 123); const auto expected = ExpectedData<0, 0, 0x00, 0x00, 0x00, 0x80, 0>("%x%lld%1.2f%s"); @@ -172,9 +172,9 @@ TEST_F(TokenizeToGlobalHandlerWithPayload, Variety) { 0ll, -0.0, ""); - ASSERT_TRUE(expected.size() == message_size_bytes_); - EXPECT_TRUE(std::memcmp(expected.data(), message_, expected.size()) == 0); - EXPECT_TRUE(payload_ == 123); + ASSERT_EQ(expected.size(), message_size_bytes_); + EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0); + EXPECT_EQ(payload_, 123); PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD( static_cast(-543), @@ -183,9 +183,9 @@ TEST_F(TokenizeToGlobalHandlerWithPayload, Variety) { 0ll, -0.0, ""); - ASSERT_TRUE(expected.size() == message_size_bytes_); - EXPECT_TRUE(std::memcmp(expected.data(), message_, expected.size()) == 0); - EXPECT_TRUE(payload_ == -543); + ASSERT_EQ(expected.size(), message_size_bytes_); + EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0); + EXPECT_EQ(payload_, -543); } extern "C" void pw_tokenizer_HandleEncodedMessageWithPayload( diff --git a/pw_unit_test/public/pw_unit_test/framework.h b/pw_unit_test/public/pw_unit_test/framework.h index 6ba5d94107..2a3ce6fa5c 100644 --- a/pw_unit_test/public/pw_unit_test/framework.h +++ b/pw_unit_test/public/pw_unit_test/framework.h @@ -458,7 +458,6 @@ inline void SetTestSuitesToRun(std::span test_suites) { }, \ #op) -// Implement boolean expectations in a C++11-compatible way. #define _PW_EXPECT_BOOL(expr, value) \ ::pw::unit_test::internal::Framework::Get().CurrentTestExpect( \ [](bool lhs, bool rhs) { return lhs == rhs; }, \ diff --git a/pw_varint/docs.rst b/pw_varint/docs.rst index 58c90f9596..ad929a1c7e 100644 --- a/pw_varint/docs.rst +++ b/pw_varint/docs.rst @@ -14,7 +14,7 @@ use a variable-length encoding for integers. Compatibility ============= * C -* C++11 (with :doc:`../pw_polyfill/docs`) +* C++14 (with :doc:`../pw_polyfill/docs`) API ===