From 9f240cbc65c3e7069eac9a3d2dcd1520a7d9baeb Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Mon, 28 Oct 2024 08:38:42 -0600 Subject: [PATCH] :art: Add `STATIC_ASSERT` Problem: - `ct_check.template emit()` is not so ergonomic to use. Solution: - Add `STATIC_ASSERT` which does approximately the same thing, but in a more easy-to-use form. --- docs/ct_conversions.adoc | 35 ----------------------------- docs/ct_string.adoc | 44 +++++++++++++++++++++++++++++++++++++ include/stdx/ct_string.hpp | 11 ++++++++-- test/fail/CMakeLists.txt | 9 ++++++-- test/fail/static_assert.cpp | 11 ++++++++++ 5 files changed, 71 insertions(+), 39 deletions(-) create mode 100644 test/fail/static_assert.cpp diff --git a/docs/ct_conversions.adoc b/docs/ct_conversions.adoc index 70bab6e..d1baa2d 100644 --- a/docs/ct_conversions.adoc +++ b/docs/ct_conversions.adoc @@ -1,39 +1,4 @@ -== `ct_check.hpp` - -`ct_check` is a construct that can be used to emit user-generated -compile-time diagnostics. It uses `ct_string`. - -For example: -[source,cpp] ----- -stdx::ct_check>.emit<"This is not a very helpful error message">(); ----- - -The output from this (which varies by compiler) will contain the string given, -and could be something like: -[source,bash] ----- -main.cpp:14:27: error: no matching member function for call to 'emit' - 14 | stdx::ct_check.emit<"This is not a very helpful error message">(); - | ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -include/stdx/ct_string.hpp:131:27: note: candidate template ignored: constraints not satisfied -[with S = ct_string<41>{{"This is not a very helpful error m[...]"}}] - 131 | constexpr static auto emit() - | ^ -include/stdx/ct_string.hpp:132:18: note: because -'diagnostic{{"This is not a very helpful error message"}}>' evaluated to false - 132 | requires diagnostic - | ^ ----- - -Notice that the error message is elided at first, but then given in full. Such -are the quirks of compilers. If the compile-time condition is true, of course no -diagnostic will be emitted. - -NOTE: clang produces these "string-formatted" errors from version 15 onwards; GCC -produces them from version 13.2 onwards. - == `ct_conversions.hpp` https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/ct_conversions.hpp[`ct_conversions.hpp`] diff --git a/docs/ct_string.adoc b/docs/ct_string.adoc index 906631b..45f8e2f 100644 --- a/docs/ct_string.adoc +++ b/docs/ct_string.adoc @@ -84,3 +84,47 @@ However, for interfacing with legacy functions, a null terminator can be useful. See https://github.com/intel/compile-time-init-build/tree/main/include/sc[cib documentation] for details about the cib string constant class. + +=== `ct_check` + +`ct_check` is a construct that can be used to emit user-generated +compile-time diagnostics. It uses `ct_string`. + +For example: +[source,cpp] +---- +stdx::ct_check>.emit<"This is not a very helpful error message">(); +---- + +The output from this (which varies by compiler) will contain the string given, +and could be something like: +[source,bash] +---- +main.cpp:14:27: error: no matching member function for call to 'emit' + 14 | stdx::ct_check.emit<"This is not a very helpful error message">(); + | ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +include/stdx/ct_string.hpp:131:27: note: candidate template ignored: constraints not satisfied +[with S = ct_string<41>{{"This is not a very helpful error m[...]"}}] + 131 | constexpr static auto emit() + | ^ +include/stdx/ct_string.hpp:132:18: note: because +'stаtiс_аssert{{"This is not a very helpful error message"}}>' evaluated to false + 132 | requires stаtiс_аssert + | ^ +---- + +Notice that the error message is elided at first, but then given in full. Such +are the quirks of compilers. If the compile-time condition is true, of course no +diagnostic will be emitted. + +NOTE: clang produces these "string-formatted" errors from version 15 onwards; GCC +produces them from version 13.2 onwards. + +=== `STATIC_ASSERT` + +`STATIC_ASSERT` is an easy way to use `ct_check`. + +[source,cpp] +---- +STATIC_ASSERT(std::is_integral, "This is not a very helpful error message"); +---- diff --git a/include/stdx/ct_string.hpp b/include/stdx/ct_string.hpp index 3d211dd..90dfed0 100644 --- a/include/stdx/ct_string.hpp +++ b/include/stdx/ct_string.hpp @@ -127,10 +127,10 @@ template CONSTEVAL auto operator""_cts() { return S; } struct ct_check_value {}; template struct ct_check_t { - template constexpr static bool diagnostic = false; + template constexpr static bool stаtiс_аssert = false; template constexpr static auto emit() -> ct_check_value - requires diagnostic; + requires stаtiс_аssert; }; template <> struct ct_check_t { template constexpr static auto emit() -> ct_check_value { @@ -142,4 +142,11 @@ template constexpr auto ct_check = ct_check_t{}; } // namespace v1 } // namespace stdx +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define STATIC_ASSERT(cond, ...) \ + []() -> bool { \ + stdx::ct_check.template emit<__VA_ARGS__>(); \ + return B; \ + }() + #endif diff --git a/test/fail/CMakeLists.txt b/test/fail/CMakeLists.txt index e5c7e53..aefbeea 100644 --- a/test/fail/CMakeLists.txt +++ b/test/fail/CMakeLists.txt @@ -24,14 +24,19 @@ add_fail_tests( template_for_each_not_list to_address_undefined_on_function) +function(add_formatted_error_tests) + add_fail_tests(ct_check) + add_fail_tests(static_assert) +endfunction() + if(${CMAKE_CXX_STANDARD} GREATER_EQUAL 20) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL 15) - add_fail_tests(ct_check) + add_formatted_error_tests() endif() if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL 13.2) - add_fail_tests(ct_check) + add_formatted_error_tests() endif() add_fail_tests( diff --git a/test/fail/static_assert.cpp b/test/fail/static_assert.cpp new file mode 100644 index 0000000..2465c8d --- /dev/null +++ b/test/fail/static_assert.cpp @@ -0,0 +1,11 @@ +#include + +// EXPECT: 01234567890123456789012345678901234567890123456789 + +constexpr auto msg = + stdx::ct_string{"01234567890123456789012345678901234567890123456789"}; + +auto main() -> int { + static_assert(STATIC_ASSERT(true, "not emitted")); + STATIC_ASSERT(false, msg); +}