From 265ac25bbc984acbd9c12743cc96d8e8b0acf01b Mon Sep 17 00:00:00 2001 From: Toni Neubert Date: Wed, 1 Nov 2023 22:59:00 +0100 Subject: [PATCH] refactor: make code compatible with gcc 11/12/13 and clang 16/17 (#76) --- .clang-tidy | 3 ++ .github/workflows/ci.yml | 38 +++++++++----- cmake/dev-mode.cmake | 2 +- include/emio/detail/conversion.hpp | 6 +-- include/emio/detail/format/formatter.hpp | 12 +++-- include/emio/detail/format/ranges.hpp | 42 +++++++--------- include/emio/detail/scan/scanner.hpp | 12 +++-- include/emio/detail/validated_string.hpp | 1 + include/emio/format.hpp | 63 ++++++++++++------------ include/emio/formatter.hpp | 6 +-- include/emio/reader.hpp | 11 ++--- test/benchmark/bench_format.cpp | 4 +- test/static_analysis/test_main.cpp | 2 +- test/unit_test/detail/test_dragon.cpp | 4 +- 14 files changed, 114 insertions(+), 92 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 565b8c75..a1b5e548 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -45,6 +45,9 @@ Checks: > -bugprone-exception-escape, -cppcoreguidelines-pro-bounds-pointer-arithmetic, -cppcoreguidelines-pro-bounds-constant-array-index, + -cppcoreguidelines-avoid-do-while, + -cppcoreguidelines-avoid-const-or-ref-data-members, + WarningsAsErrors: '' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa4c8d1c..5f7c03d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,12 +22,12 @@ jobs: - name: Install clang-format and clang-tidy run: | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main' - sudo apt update && sudo apt install -y clang-format-15 clang-tidy-15 + sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main' + sudo apt update && sudo apt install -y clang-format-17 clang-tidy-17 sudo update-alternatives --remove-all clang-format || true sudo update-alternatives --remove-all clang-tidy || true - sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 1000 - sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-15 1000 + sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-17 1000 + sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-17 1000 clang-tidy --version clang-format --version @@ -43,7 +43,7 @@ jobs: unit-tests: strategy: matrix: - compiler: [ gcc, clang ] + compiler: [ gcc-11, gcc-12, gcc-13, clang-16, clang-17 ] build_type: [ Debug, Release ] runs-on: ubuntu-22.04 @@ -53,16 +53,32 @@ jobs: - name: Install Compiler run: | - if [[ "$compiler" == "gcc" ]]; then + if [[ "$compiler" == "gcc-11" ]]; then sudo apt update && sudo apt install -y gcc-11 g++-11 echo "CC=gcc-11" >> $GITHUB_ENV echo "CXX=g++-11" >> $GITHUB_ENV - else + elif [[ "$compiler" == "gcc-12" ]]; then + sudo apt update && sudo apt install -y gcc-12 g++-12 + echo "CC=gcc-12" >> $GITHUB_ENV + echo "CXX=g++-12" >> $GITHUB_ENV + elif [[ "$compiler" == "gcc-13" ]]; then + sudo apt-get install build-essential software-properties-common -y + sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + sudo apt update && sudo apt install -y gcc-13 g++-13 + echo "CC=gcc-13" >> $GITHUB_ENV + echo "CXX=g++-13" >> $GITHUB_ENV + elif [[ "$compiler" == "clang-16" ]]; then wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main' - sudo apt update && sudo apt install -y clang-15 - echo "CC=clang-15" >> $GITHUB_ENV - echo "CXX=clang++-15" >> $GITHUB_ENV + sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main' + sudo apt update && sudo apt install -y clang-16 + echo "CC=clang-16" >> $GITHUB_ENV + echo "CXX=clang++-16" >> $GITHUB_ENV + elif [[ "$compiler" == "clang-17" ]]; then + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main' + sudo apt update && sudo apt install -y clang-17 + echo "CC=clang-17" >> $GITHUB_ENV + echo "CXX=clang++-17" >> $GITHUB_ENV fi env: compiler: ${{ matrix.compiler }} diff --git a/cmake/dev-mode.cmake b/cmake/dev-mode.cmake index 33fd9f21..2fe3d244 100644 --- a/cmake/dev-mode.cmake +++ b/cmake/dev-mode.cmake @@ -34,7 +34,7 @@ if (BUILD_TESTING) Include(FetchContent) FetchContent_Declare( Catch2 - GIT_TAG v3.1.0 + GIT_TAG v3.4.0 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_SHALLOW TRUE ) diff --git a/include/emio/detail/conversion.hpp b/include/emio/detail/conversion.hpp index 30b0d09e..b14516b4 100644 --- a/include/emio/detail/conversion.hpp +++ b/include/emio/detail/conversion.hpp @@ -95,11 +95,11 @@ constexpr size_t count_digits(T number) noexcept { if constexpr (Base == 10) { return count_digits_10(number); } else if constexpr (Base == 2) { - return std::bit_width(number); + return static_cast(std::bit_width(number)); } else if constexpr (Base == 8) { - return (std::bit_width(number) + 2) / 3; + return static_cast((std::bit_width(number) + 2) / 3); } else if constexpr (Base == 16) { - return (std::bit_width(number) + 3) / 4; + return static_cast(((std::bit_width(number) + 3) / 4)); } else { size_t digit_cnt{1}; for (number /= static_cast(Base); number; number /= static_cast(Base)) { diff --git a/include/emio/detail/format/formatter.hpp b/include/emio/detail/format/formatter.hpp index bb872bea..26ae68f0 100644 --- a/include/emio/detail/format/formatter.hpp +++ b/include/emio/detail/format/formatter.hpp @@ -60,7 +60,7 @@ inline constexpr result write_padding_right(writer& out, format_specs& spe } template -constexpr result write_padded(writer& out, format_specs& specs, size_t width, Func&& func) noexcept { +constexpr result write_padded(writer& out, format_specs& specs, size_t width, const Func& func) noexcept { if (specs.align == alignment::none) { specs.align = DefaultAlign; } @@ -705,8 +705,9 @@ inline constexpr result check_integral_specs(const format_specs& specs) no case 'o': case 'O': return success; + default: + return err::invalid_format; } - return err::invalid_format; } inline constexpr result check_unsigned_specs(const format_specs& specs) noexcept { @@ -762,8 +763,9 @@ inline constexpr result check_floating_point_specs(const format_specs& spe // case 'a': Not supported yet. // case 'A': return success; + default: + return err::invalid_format; } - return err::invalid_format; } inline constexpr result check_string_specs(const format_specs& specs) noexcept { @@ -785,8 +787,8 @@ inline constexpr bool has_formatter_v = std::is_constructible_v>; template concept has_validate_function_v = requires { - { formatter::validate(std::declval()) } -> std::same_as>; - }; + { formatter::validate(std::declval()) } -> std::same_as>; +}; template concept has_any_validate_function_v = diff --git a/include/emio/detail/format/ranges.hpp b/include/emio/detail/format/ranges.hpp index ba00f11a..83cfd30f 100644 --- a/include/emio/detail/format/ranges.hpp +++ b/include/emio/detail/format/ranges.hpp @@ -28,10 +28,10 @@ concept advanceable = requires(T x) { ++x; }; template concept is_iterable = std::is_array_v || requires(T x) { - { begin(x) } -> advanceable; - requires !std::is_same_v; - { static_cast(begin(x) != end(x)) }; - }; + { begin(x) } -> advanceable; + requires !std::is_same_v; + { static_cast(begin(x) != end(x)) }; +}; template using element_type_t = std::remove_cvref_t&>()))>; @@ -46,8 +46,7 @@ template concept is_string_like = std::is_constructible_v; template -concept is_valid_range = is_iterable && ! -is_string_like&& is_formattable_v>; +concept is_valid_range = is_iterable && !is_string_like && is_formattable_v>; template struct is_span : std::false_type {}; @@ -56,12 +55,11 @@ template struct is_span> : std::true_type {}; template -concept is_contiguous_but_not_span = - std::is_array_v || requires(T x) { - requires !is_span::value; - requires std::is_same_v, element_type_t>; - { size(x) } -> std::same_as; - }; +concept is_contiguous_but_not_span = std::is_array_v || requires(T x) { + requires !is_span::value; + requires std::is_same_v, element_type_t>; + { size(x) } -> std::same_as; +}; struct ranges_specs { std::string_view opening_bracket{}; @@ -85,9 +83,9 @@ using std::get; // From https://stackoverflow.com/a/68444475/1611317 template concept has_tuple_element = requires(T t) { - typename std::tuple_element_t>; - { get(t) } -> std::convertible_to&>; - }; + typename std::tuple_element_t>; + { get(t) } -> std::convertible_to&>; +}; template constexpr auto has_tuple_element_unpack(std::index_sequence /*unused*/) noexcept { @@ -95,12 +93,10 @@ constexpr auto has_tuple_element_unpack(std::index_sequence /*unused*/) n } template -concept is_tuple_like = ! -std::is_reference_v&& requires(T t) { - typename std::tuple_size::type; - requires std::derived_from, - std::integral_constant>>; - } && has_tuple_element_unpack(std::make_index_sequence>()); +concept is_tuple_like = !std::is_reference_v && requires(T t) { + typename std::tuple_size::type; + requires std::derived_from, std::integral_constant>>; +} && has_tuple_element_unpack(std::make_index_sequence>()); template constexpr auto is_formattable_unpack(std::index_sequence /*unused*/) noexcept { @@ -108,8 +104,8 @@ constexpr auto is_formattable_unpack(std::index_sequence /*unused*/) noex } template -concept is_valid_tuple = ! -is_valid_range&& is_tuple_like&& is_formattable_unpack(std::make_index_sequence>()); +concept is_valid_tuple = !is_valid_range && is_tuple_like && + is_formattable_unpack(std::make_index_sequence>()); template auto get_tuple_formatters(std::index_sequence /*unused*/) diff --git a/include/emio/detail/scan/scanner.hpp b/include/emio/detail/scan/scanner.hpp index 2aef381a..7d05ead7 100644 --- a/include/emio/detail/scan/scanner.hpp +++ b/include/emio/detail/scan/scanner.hpp @@ -60,9 +60,10 @@ inline constexpr int get_base(char type) noexcept { return 10; case 'x': return 16; + default: + EMIO_Z_DEV_ASSERT(false); + EMIO_Z_INTERNAL_UNREACHABLE; } - EMIO_Z_DEV_ASSERT(false); - EMIO_Z_INTERNAL_UNREACHABLE; } inline constexpr result parse_alternate_form(reader& in, int base) noexcept { @@ -305,8 +306,9 @@ inline constexpr result check_integral_specs(const format_specs& specs) no case 'o': case 'x': return success; + default: + return err::invalid_format; } - return err::invalid_format; } inline constexpr result check_string_specs(const format_specs& specs) noexcept { @@ -326,8 +328,8 @@ inline constexpr bool has_scanner_v = std::is_constructible_v>; template concept has_validate_function_v = requires { - { scanner::validate(std::declval()) } -> std::same_as>; - }; + { scanner::validate(std::declval()) } -> std::same_as>; +}; template concept has_any_validate_function_v = diff --git a/include/emio/detail/validated_string.hpp b/include/emio/detail/validated_string.hpp index 037c5d2d..b570daee 100644 --- a/include/emio/detail/validated_string.hpp +++ b/include/emio/detail/validated_string.hpp @@ -27,6 +27,7 @@ class runtime_string { constexpr runtime_string() = default; // Don't allow temporary strings or any nullptr. + // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved): as intended constexpr runtime_string(std::string&&) = delete; constexpr runtime_string(std::nullptr_t) = delete; constexpr runtime_string(int) = delete; diff --git a/include/emio/format.hpp b/include/emio/format.hpp index 3322deeb..d9c952a4 100644 --- a/include/emio/format.hpp +++ b/include/emio/format.hpp @@ -40,7 +40,7 @@ using valid_format_string = detail::format::valid_format_string; */ template [[nodiscard]] detail::args_storage make_format_args( - format_string format_str, const Args&... args) noexcept { + emio::format_string format_str, const Args&... args) noexcept { return {format_str, args...}; } @@ -50,7 +50,7 @@ template * @return The total number of characters in the formatted string or invalid_format if the format string validation * failed. */ -inline result vformatted_size(format_args&& args) noexcept { +inline result vformatted_size(const format_args& args) noexcept { detail::counting_buffer buf{}; EMIO_TRYV(detail::format::vformat_to(buf, args)); return buf.count(); @@ -69,7 +69,7 @@ template if (EMIO_Z_INTERNAL_IS_CONST_EVAL) { detail::format::format_to(buf, format_str, args...).value(); } else { - detail::format::vformat_to(buf, make_format_args(format_str, args...)).value(); + detail::format::vformat_to(buf, emio::make_format_args(format_str, args...)).value(); } return buf.count(); } @@ -82,10 +82,10 @@ template * validation failed. */ template - requires(std::is_same_v || std::is_same_v>) + requires(std::is_same_v || std::is_same_v>) constexpr result formatted_size(T format_str, const Args&... args) noexcept { detail::counting_buffer buf{}; - format_string str{format_str}; + emio::format_string str{format_str}; EMIO_TRYV(detail::format::format_to(buf, str, args...)); return buf.count(); } @@ -135,11 +135,11 @@ constexpr result vformat_to(OutputIt out, const format_args& args) noe * @return Success or EOF if the buffer is to small or invalid_format if the format string validation failed. */ template -constexpr result format_to(buffer& buf, format_string format_str, const Args&... args) noexcept { +constexpr result format_to(buffer& buf, emio::format_string format_str, const Args&... args) noexcept { if (EMIO_Z_INTERNAL_IS_CONST_EVAL) { EMIO_TRYV(detail::format::format_to(buf, format_str, args...)); } else { - EMIO_TRYV(detail::format::vformat_to(buf, make_format_args(format_str, args...))); + EMIO_TRYV(detail::format::vformat_to(buf, emio::make_format_args(format_str, args...))); } return success; } @@ -152,11 +152,11 @@ constexpr result format_to(buffer& buf, format_string format_str, * @return Success or EOF if the buffer is to small or invalid_format if the format string validation failed. */ template -constexpr result format_to(writer& out, format_string format_str, const Args&... args) noexcept { +constexpr result format_to(writer& out, emio::format_string format_str, const Args&... args) noexcept { if (EMIO_Z_INTERNAL_IS_CONST_EVAL) { EMIO_TRYV(detail::format::format_to(out.get_buffer(), format_str, args...)); } else { - EMIO_TRYV(detail::format::vformat_to(out.get_buffer(), make_format_args(format_str, args...))); + EMIO_TRYV(detail::format::vformat_to(out.get_buffer(), emio::make_format_args(format_str, args...))); } return success; } @@ -170,12 +170,13 @@ constexpr result format_to(writer& out, format_string format_str, */ template requires(std::output_iterator) -constexpr result format_to(OutputIt out, format_string format_str, const Args&... args) noexcept { +constexpr result format_to(OutputIt out, emio::format_string format_str, + const Args&... args) noexcept { iterator_buffer buf{out}; if (EMIO_Z_INTERNAL_IS_CONST_EVAL) { EMIO_TRYV(detail::format::format_to(buf, format_str, args...)); } else { - EMIO_TRYV(detail::format::vformat_to(buf, make_format_args(format_str, args...))); + EMIO_TRYV(detail::format::vformat_to(buf, emio::make_format_args(format_str, args...))); } return buf.out(); } @@ -201,9 +202,9 @@ inline result vformat(const format_args& args) noexcept { * @return The string. */ template -[[nodiscard]] std::string format(valid_format_string format_str, +[[nodiscard]] std::string format(emio::valid_format_string format_str, const Args&... args) noexcept(detail::exceptions_disabled) { - return vformat(make_format_args(format_str, args...)).value(); // Should never fail. + return emio::vformat(emio::make_format_args(format_str, args...)).value(); // Should never fail. } /** @@ -214,9 +215,9 @@ template * failed. */ template - requires(std::is_same_v || std::is_same_v>) + requires(std::is_same_v || std::is_same_v>) result format(T format_str, const Args&... args) noexcept { - return vformat(make_format_args(format_str, args...)); + return emio::vformat(emio::make_format_args(format_str, args...)); } /** @@ -278,14 +279,14 @@ result vformat_to_n(buffer& buf, size_t n, const format_args& args) noex template requires(std::output_iterator) constexpr result> format_to_n(OutputIt out, std::iter_difference_t n, - format_string format_str, + emio::format_string format_str, const Args&... args) noexcept { truncating_iterator tout{out, static_cast(n)}; iterator_buffer buf{tout}; if (EMIO_Z_INTERNAL_IS_CONST_EVAL) { EMIO_TRYV(detail::format::format_to(buf, format_str, args...)); } else { - EMIO_TRYV(detail::format::vformat_to(buf, make_format_args(format_str, args...))); + EMIO_TRYV(detail::format::vformat_to(buf, emio::make_format_args(format_str, args...))); } EMIO_TRYV(buf.flush()); tout = buf.out(); @@ -303,13 +304,13 @@ constexpr result> format_to_n(OutputIt out, std::it * the format string validation failed. */ template -constexpr result format_to_n(buffer& buf, size_t n, format_string format_str, +constexpr result format_to_n(buffer& buf, size_t n, emio::format_string format_str, const Args&... args) noexcept { truncating_buffer trunc_buf{buf, n}; if (EMIO_Z_INTERNAL_IS_CONST_EVAL) { EMIO_TRYV(detail::format::format_to(trunc_buf, format_str, args...)); } else { - EMIO_TRYV(detail::format::vformat_to(trunc_buf, make_format_args(format_str, args...))); + EMIO_TRYV(detail::format::vformat_to(trunc_buf, emio::make_format_args(format_str, args...))); } EMIO_TRYV(trunc_buf.flush()); return trunc_buf.count(); @@ -337,8 +338,8 @@ inline result vprint(std::FILE* file, const format_args& args) noexcept { * @param args The format args with the format string. */ template -void print(valid_format_string format_str, const Args&... args) noexcept { - vprint(stdout, make_format_args(format_str, args...)).value(); // Should never fail. +void print(emio::valid_format_string format_str, const Args&... args) noexcept { + vprint(stdout, emio::make_format_args(format_str, args...)).value(); // Should never fail. } /** @@ -348,9 +349,9 @@ void print(valid_format_string format_str, const Args&... args) noexcep * @return Success or EOF if the file stream is not writable or invalid_format if the format string validation failed. */ template - requires(std::is_same_v || std::is_same_v>) + requires(std::is_same_v || std::is_same_v>) result print(T format_str, const Args&... args) noexcept { - return vprint(stdout, make_format_args(format_str, args...)); + return vprint(stdout, emio::make_format_args(format_str, args...)); } /** @@ -361,8 +362,8 @@ result print(T format_str, const Args&... args) noexcept { * @return Success or EOF if the file stream is not writable or invalid_format if the format string validation failed. */ template -result print(std::FILE* file, format_string format_str, const Args&... args) noexcept { - return vprint(file, make_format_args(format_str, args...)); +result print(std::FILE* file, emio::format_string format_str, const Args&... args) noexcept { + return vprint(file, emio::make_format_args(format_str, args...)); } /** @@ -391,8 +392,8 @@ inline result vprintln(std::FILE* file, const format_args& args) noexcept * @param args The arguments to be formatted. */ template -void println(valid_format_string format_str, const Args&... args) noexcept { - vprintln(stdout, make_format_args(format_str, args...)).value(); // Should never fail. +void println(emio::valid_format_string format_str, const Args&... args) noexcept { + vprintln(stdout, emio::make_format_args(format_str, args...)).value(); // Should never fail. } /** @@ -404,9 +405,9 @@ void println(valid_format_string format_str, const Args&... args) noexc * failed. */ template - requires(std::is_same_v || std::is_same_v>) + requires(std::is_same_v || std::is_same_v>) result println(T format_str, const Args&... args) noexcept { - return vprintln(stdout, make_format_args(format_str, args...)); + return vprintln(stdout, emio::make_format_args(format_str, args...)); } /** @@ -417,8 +418,8 @@ result println(T format_str, const Args&... args) noexcept { * @return Success or EOF if the file stream is not writable or invalid_format if the format string validation failed. */ template -result println(std::FILE* file, format_string format_str, const Args&... args) noexcept { - return vprintln(file, make_format_args(format_str, args...)); +result println(std::FILE* file, emio::format_string format_str, const Args&... args) noexcept { + return vprintln(file, emio::make_format_args(format_str, args...)); } } // namespace emio diff --git a/include/emio/formatter.hpp b/include/emio/formatter.hpp index 6c5569f1..905c797f 100644 --- a/include/emio/formatter.hpp +++ b/include/emio/formatter.hpp @@ -252,9 +252,9 @@ class formatter> { private: template requires requires(F x) { - x.set_width(1); - x.set_precision(1); - } + x.set_width(1); + x.set_precision(1); + } static constexpr F& get_core_formatter(F& formatter) noexcept { return formatter; } diff --git a/include/emio/reader.hpp b/include/emio/reader.hpp index 4ef3fe50..0e25f86f 100644 --- a/include/emio/reader.hpp +++ b/include/emio/reader.hpp @@ -50,7 +50,7 @@ class reader { constexpr reader() = default; // Don't allow temporary strings or any nullptr. - constexpr reader(std::string&&) = delete; + constexpr reader(std::string&&) = delete; // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved): as intended constexpr reader(std::nullptr_t) = delete; constexpr reader(int) = delete; @@ -61,7 +61,7 @@ class reader { template requires(std::is_constructible_v && !std::is_same_v) // NOLINTNEXTLINE(bugprone-forwarding-reference-overload): Is guarded by require clause. - constexpr explicit reader(Arg&& input) noexcept : reader{std::string_view{input}} {} + constexpr explicit reader(Arg&& input) noexcept : reader{std::string_view{std::forward(input)}} {} /** * Constructs the reader from a string view. @@ -287,10 +287,9 @@ class reader { */ template requires(std::is_invocable_r_v) - constexpr result read_until( - Predicate&& predicate, - const read_until_options& options = - default_read_until_options()) noexcept(std::is_nothrow_invocable_r_v) { + constexpr result + read_until(const Predicate& predicate, const read_until_options& options = default_read_until_options()) noexcept( + std::is_nothrow_invocable_r_v) { return read_until_match(std::find_if(it_, end_, predicate), options); } diff --git a/test/benchmark/bench_format.cpp b/test/benchmark/bench_format.cpp index 2e8cf42d..6873c4c2 100644 --- a/test/benchmark/bench_format.cpp +++ b/test/benchmark/bench_format.cpp @@ -1,9 +1,9 @@ // Unit under test. -#include - #include // Other includes. +#include + #include #include #include diff --git a/test/static_analysis/test_main.cpp b/test/static_analysis/test_main.cpp index 16e59a12..e43223e5 100644 --- a/test/static_analysis/test_main.cpp +++ b/test/static_analysis/test_main.cpp @@ -1,5 +1,5 @@ // Include all. -#include +#include // NOLINT(misc-include-cleaner): required to parse all headers with static analysers int main() { return 0; diff --git a/test/unit_test/detail/test_dragon.cpp b/test/unit_test/detail/test_dragon.cpp index e2e7010d..94c9bd8e 100644 --- a/test/unit_test/detail/test_dragon.cpp +++ b/test/unit_test/detail/test_dragon.cpp @@ -135,7 +135,9 @@ void check_shortest(double d, std::string_view expected_str, int16_t expected_k) } #define CHECK_SHORTEST(d, exp_str, exp_k) \ - SECTION(#d) { check_shortest(d, exp_str, exp_k); } + SECTION(#d) { \ + check_shortest(d, exp_str, exp_k); \ + } TEST_CASE("format_shortest") { // 0.0999999999999999777955395074968691915273...