From 5248cd724e5552c1214ab9b52af6ef5425639fa2 Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Tue, 24 Sep 2024 10:38:15 -0600 Subject: [PATCH 1/2] :art: Move `STDX_PRAGMA` to `compiler.hpp` --- include/stdx/compiler.hpp | 7 +++++++ include/stdx/utility.hpp | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/stdx/compiler.hpp b/include/stdx/compiler.hpp index 3443088..4b08cb6 100644 --- a/include/stdx/compiler.hpp +++ b/include/stdx/compiler.hpp @@ -43,3 +43,10 @@ #define LIFETIMEBOUND #endif #endif + +#define STDX_DO_PRAGMA(X) _Pragma(#X) +#ifdef __clang__ +#define STDX_PRAGMA(X) STDX_DO_PRAGMA(clang X) +#else +#define STDX_PRAGMA(X) STDX_DO_PRAGMA(GCC X) +#endif diff --git a/include/stdx/utility.hpp b/include/stdx/utility.hpp index afded1e..66b9cab 100644 --- a/include/stdx/utility.hpp +++ b/include/stdx/utility.hpp @@ -186,13 +186,6 @@ constexpr auto is_aligned_with = [](auto v) -> bool { #define FWD(x) std::forward(x) #endif -#define STDX_DO_PRAGMA(X) _Pragma(#X) -#ifdef __clang__ -#define STDX_PRAGMA(X) STDX_DO_PRAGMA(clang X) -#else -#define STDX_PRAGMA(X) STDX_DO_PRAGMA(GCC X) -#endif - #ifndef CX_VALUE #define CX_VALUE(...) \ [] { \ From 8b294fbcc8063829f341d86435be04968c6d8053 Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Tue, 24 Sep 2024 10:41:55 -0600 Subject: [PATCH 2/2] :sparkles: Add compile-time diagnostic `ct_check` Problem: - There is no way to produce a user-formatted compile-time diagnostic. Solution: - Add `ct_check` to test a condition at compile-time and produce a `ct_string` message on failure. Note: - A constraint check is the key to prevent the compiler from eliding the string. --- docs/ct_conversions.adoc | 35 +++++++++++++++++++++++++++++++++++ include/stdx/ct_string.hpp | 11 +++++++++++ test/fail/CMakeLists.txt | 9 +++++++++ test/fail/ct_check.cpp | 11 +++++++++++ 4 files changed, 66 insertions(+) create mode 100644 test/fail/ct_check.cpp diff --git a/docs/ct_conversions.adoc b/docs/ct_conversions.adoc index d1baa2d..70bab6e 100644 --- a/docs/ct_conversions.adoc +++ b/docs/ct_conversions.adoc @@ -1,4 +1,39 @@ +== `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/include/stdx/ct_string.hpp b/include/stdx/ct_string.hpp index 70b153f..59b599c 100644 --- a/include/stdx/ct_string.hpp +++ b/include/stdx/ct_string.hpp @@ -124,6 +124,17 @@ template CONSTEVAL auto operator""_cts() { return S; } } // namespace ct_string_literals } // namespace literals +template struct ct_check_t { + template constexpr static bool diagnostic = false; + template + constexpr static auto emit() -> void + requires diagnostic; +}; +template <> struct ct_check_t { + template constexpr static auto emit() -> void {} +}; +template constexpr auto ct_check = ct_check_t{}; + } // namespace v1 } // namespace stdx diff --git a/test/fail/CMakeLists.txt b/test/fail/CMakeLists.txt index ac3736b..4b9e93c 100644 --- a/test/fail/CMakeLists.txt +++ b/test/fail/CMakeLists.txt @@ -25,6 +25,15 @@ add_fail_tests( to_address_undefined_on_function) 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) + endif() + if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION} + VERSION_GREATER_EQUAL 13.2) + add_fail_tests(ct_check) + endif() + add_fail_tests( dynamic_span_no_ct_capacity dynamic_container_no_ct_capacity diff --git a/test/fail/ct_check.cpp b/test/fail/ct_check.cpp new file mode 100644 index 0000000..5e70847 --- /dev/null +++ b/test/fail/ct_check.cpp @@ -0,0 +1,11 @@ +#include + +// EXPECT: 01234567890123456789012345678901234567890123456789 + +constexpr auto msg = + stdx::ct_string{"01234567890123456789012345678901234567890123456789"}; + +auto main() -> int { + stdx::ct_check.emit<"not emitted">(); + stdx::ct_check.emit(); +}