From 5c45405d7ec5f377a1f52c90471e1a5a4e6f9a5e Mon Sep 17 00:00:00 2001 From: Benedek Thaler Date: Thu, 22 Sep 2022 17:23:10 +0200 Subject: [PATCH 1/3] Add BINLOG_ADAPT_CONCEPT --- CMakeLists.txt | 4 + doc/UserGuide.md | 4 + include/binlog/adapt_struct.hpp | 37 +++++++++ test/integration/IntegrationTest.cpp | 6 ++ test/integration/LoggingAdaptedConcepts.cpp | 86 +++++++++++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 test/integration/LoggingAdaptedConcepts.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c58a1d6..e9ffba4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -336,6 +336,10 @@ add_example(TscClock) add_inttest(LoggingVariants) endif() + if(${CMAKE_CXX_STANDARD} GREATER_EQUAL 20) + add_inttest(LoggingAdaptedConcepts) + endif() + if(Boost_FOUND) target_compile_definitions(IntegrationTest PRIVATE BINLOG_HAS_BOOST) diff --git a/doc/UserGuide.md b/doc/UserGuide.md index c5763e1..10c1036 100644 --- a/doc/UserGuide.md +++ b/doc/UserGuide.md @@ -198,6 +198,10 @@ User defined templates can be adapted for logging in a similar way: [catchfile test/integration/LoggingAdaptedStructs.cpp adapt_template] +As of C++20, concepts can be also adapted for logging: + + [catchfile test/integration/LoggingAdaptedConcepts.cpp concept] + For more information see the Mserialize documentation on [Adapting custom types][mserialize-act] and [Adapting user defined recursive types for visitation][mserialize-rec]. diff --git a/include/binlog/adapt_struct.hpp b/include/binlog/adapt_struct.hpp index baf1675..6058c24 100644 --- a/include/binlog/adapt_struct.hpp +++ b/include/binlog/adapt_struct.hpp @@ -117,6 +117,43 @@ MSERIALIZE_EXPAND(MSERIALIZE_MAKE_TEMPLATE_SERIALIZABLE(__VA_ARGS__)) \ /**/ +#if __cplusplus >= 202002L // Otherwise __VA_OPT__ breaks +/** + * BINLOG_ADAPT_CONCEPT(Concept, members...) + * + * Make types that model `Concept` loggable, in terms of the specified members. + * + * Example: + * + * template + * concept Stringable = requires(T a) + * { + * { a.str() } -> std::convertible_to; + * }; + * + * BINLOG_ADAPT_CONCEPT(Stringable, str) + * + * The macro has to be called in global scope (outside of any namespace). + * `Concept` is a Named Requirement - see C++20 concepts. + * + * members... is a list of data members or getters `Concept` requires. + * members... can be empty. + * See BINLOG_ADAPT_STRUCT for limitations. + * + * Calling this macro requires C++20 or greater. + * + * If type Foo models concept Bar, and Bar is adapted using this macro, + * when a Foo object is logged (that is otherwise not adapted), + * on the output, the type name will be "Bar", not "Foo". + * + * @see BINLOG_ADAPT_STRUCT + */ +#define BINLOG_ADAPT_CONCEPT(Concept, ...) \ + MSERIALIZE_EXPAND(MSERIALIZE_MAKE_TEMPLATE_TAG((Concept Concept), (Concept) __VA_OPT__(,) __VA_ARGS__)) \ + MSERIALIZE_EXPAND(MSERIALIZE_MAKE_TEMPLATE_SERIALIZABLE((Concept Concept), (Concept) __VA_OPT__(,) __VA_ARGS__)) \ + /**/ +#endif // >= C++20 + /** * Allow member list of BINLOG_ADAPT_STRUCT or BINLOG_ADAPT_TEMPLATE * to reference private and protected members. diff --git a/test/integration/IntegrationTest.cpp b/test/integration/IntegrationTest.cpp index bcf3c16..d74414f 100644 --- a/test/integration/IntegrationTest.cpp +++ b/test/integration/IntegrationTest.cpp @@ -126,6 +126,12 @@ TEST_CASE("LoggingVariants") { runReadDiff("LoggingVariants", "%m"); } #endif +#if __cplusplus >= 202002L + +TEST_CASE("LoggingAdaptedConcepts") { runReadDiff("LoggingAdaptedConcepts", "%m"); } + +#endif + #ifdef BINLOG_HAS_BOOST TEST_CASE("LoggingBoostTypes") { runReadDiff("LoggingBoostTypes", "%m"); } diff --git a/test/integration/LoggingAdaptedConcepts.cpp b/test/integration/LoggingAdaptedConcepts.cpp new file mode 100644 index 0000000..fc143a5 --- /dev/null +++ b/test/integration/LoggingAdaptedConcepts.cpp @@ -0,0 +1,86 @@ +#include + +#include + +// Empty + +template +concept Empty = T::is_empty::value; + +#ifdef __clang__ + // Since C++20, passing no arguments to a variadic macro is allowed, + // and we are testing wheter it works. clang 10 produces an incorrect warning. + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" +#endif + +BINLOG_ADAPT_CONCEPT(Empty) + +#ifdef __clang__ + #pragma clang diagnostic pop +#endif + +struct Nothing { + using is_empty = std::true_type; +}; + +// Concept + +//[concept +template +concept Stringable = requires(T a) +{ + { a.str() } -> std::convertible_to; +}; + +BINLOG_ADAPT_CONCEPT(Stringable, str) + +struct Foo { + std::string str() const { return "bar"; } +}; +//] + +// Concept shadowed by BINLOG_ADAPT_STRUCT + +struct Baz { + std::string str() const { return "baz"; } + int id() const { return 123; } +}; + +BINLOG_ADAPT_STRUCT(Baz, id) + +static_assert(Stringable); + +// Concept shadowed by BINLOG_ADAPT_TEMPLATE + +template +struct Wrap +{ + std::string str() const { return "wrap"; } + + A a{}; +}; + +BINLOG_ADAPT_TEMPLATE((typename A), (Wrap), a) + +static_assert(Stringable>); + +int main() +{ + BINLOG_INFO("{}", Nothing{}); + // Outputs: Empty + + //[concept + BINLOG_INFO("{}", Foo{}); + // Outputs: Stringable{ str: bar } + //] + + BINLOG_INFO("{}", Baz{}); + // Outputs: Baz{ id: 123 } + + BINLOG_INFO("{}", Wrap{456}); + // Outputs: Wrap{ a: 456 } + + binlog::consume(std::cout); + return 0; +} From 94bfdac2e6e0be018fdc9d1017ea06b4df00f681 Mon Sep 17 00:00:00 2001 From: Benedek Thaler Date: Thu, 22 Sep 2022 18:11:48 +0200 Subject: [PATCH 2/3] Add C++20 build to CI Use Clang, because GitHub Ubuntu latest image has gcc 9, that does not support concepts. clang 10 should have a better support. - https://gcc.gnu.org/projects/cxx-status.html - https://clang.llvm.org/cxx_status.html --- .github/workflows/on_pull_request.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/on_pull_request.yml b/.github/workflows/on_pull_request.yml index 4eac226..1a48b1d 100644 --- a/.github/workflows/on_pull_request.yml +++ b/.github/workflows/on_pull_request.yml @@ -99,6 +99,33 @@ jobs: cd ThreadSanitized ctest -VV + build_linux_clang_cpp20: + name: Build on Linux with Clang, C++20 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Dependencies + run: | + # remove broken packages installed by default + sudo apt remove -y clang-6.0 libclang-common-6.0-dev libclang1-6.0 libllvm6.0 + sudo apt install -y clang + - name: Configure + run: | + set -x + mkdir Clang + cd Clang + export CC=$(which clang) + export CXX=$(which clang++) + cmake -DCMAKE_CXX_STANDARD=20 .. + - name: Build + run: | + cd Clang + make -j2 VERBOSE=1 + - name: Test + run: | + cd Clang + ctest -VV + build_linux_clang_tidy: name: Build on Linux with Clang+Tidy runs-on: ubuntu-latest From 1d1f57a0364e44d294b0117d7cd8cb3ae3e4363b Mon Sep 17 00:00:00 2001 From: Benedek Thaler Date: Thu, 22 Sep 2022 21:40:56 +0200 Subject: [PATCH 3/3] Use lld if building with clang and LTO --- .github/workflows/on_pull_request.yml | 4 ++-- CMakeLists.txt | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/on_pull_request.yml b/.github/workflows/on_pull_request.yml index 1a48b1d..a0759d8 100644 --- a/.github/workflows/on_pull_request.yml +++ b/.github/workflows/on_pull_request.yml @@ -108,7 +108,7 @@ jobs: run: | # remove broken packages installed by default sudo apt remove -y clang-6.0 libclang-common-6.0-dev libclang1-6.0 libllvm6.0 - sudo apt install -y clang + sudo apt install -y clang lld - name: Configure run: | set -x @@ -135,7 +135,7 @@ jobs: run: | # remove broken packages installed by default sudo apt remove -y clang-6.0 libclang-common-6.0-dev libclang1-6.0 libllvm6.0 - sudo apt install -y clang clang-tidy + sudo apt install -y clang clang-tidy lld - name: Configure run: | set -x diff --git a/CMakeLists.txt b/CMakeLists.txt index e9ffba4..a4c7ebc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,13 @@ if(POLICY CMP0069) check_ipo_supported(RESULT BINLOG_HAS_IPO) if(BINLOG_HAS_IPO) message(STATUS "Use interprocedural optimization") + + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # avoid error when mixing clang 10 lto and ld: + # /usr/bin/ld: libbinlog.a: error adding symbols: file format not recognized + message(STATUS "Use lld") + add_link_options("-fuse-ld=lld") + endif() endif() endif()