Skip to content

Commit 8b294fb

Browse files
committed
✨ 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.
1 parent 5248cd7 commit 8b294fb

File tree

4 files changed

+66
-0
lines changed

4 files changed

+66
-0
lines changed

docs/ct_conversions.adoc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,39 @@
11

2+
== `ct_check.hpp`
3+
4+
`ct_check` is a construct that can be used to emit user-generated
5+
compile-time diagnostics. It uses `ct_string`.
6+
7+
For example:
8+
[source,cpp]
9+
----
10+
stdx::ct_check<std::is_integral<float>>.emit<"This is not a very helpful error message">();
11+
----
12+
13+
The output from this (which varies by compiler) will contain the string given,
14+
and could be something like:
15+
[source,bash]
16+
----
17+
main.cpp:14:27: error: no matching member function for call to 'emit'
18+
14 | stdx::ct_check<false>.emit<"This is not a very helpful error message">();
19+
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20+
include/stdx/ct_string.hpp:131:27: note: candidate template ignored: constraints not satisfied
21+
[with S = ct_string<41>{{"This is not a very helpful error m[...]"}}]
22+
131 | constexpr static auto emit()
23+
| ^
24+
include/stdx/ct_string.hpp:132:18: note: because
25+
'diagnostic<ct_string<41>{{"This is not a very helpful error message"}}>' evaluated to false
26+
132 | requires diagnostic<S>
27+
| ^
28+
----
29+
30+
Notice that the error message is elided at first, but then given in full. Such
31+
are the quirks of compilers. If the compile-time condition is true, of course no
32+
diagnostic will be emitted.
33+
34+
NOTE: clang produces these "string-formatted" errors from version 15 onwards; GCC
35+
produces them from version 13.2 onwards.
36+
237
== `ct_conversions.hpp`
338

439
https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/ct_conversions.hpp[`ct_conversions.hpp`]

include/stdx/ct_string.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ template <ct_string S> CONSTEVAL auto operator""_cts() { return S; }
124124
} // namespace ct_string_literals
125125
} // namespace literals
126126

127+
template <bool B> struct ct_check_t {
128+
template <ct_string S> constexpr static bool diagnostic = false;
129+
template <ct_string S>
130+
constexpr static auto emit() -> void
131+
requires diagnostic<S>;
132+
};
133+
template <> struct ct_check_t<true> {
134+
template <ct_string S> constexpr static auto emit() -> void {}
135+
};
136+
template <bool B> constexpr auto ct_check = ct_check_t<B>{};
137+
127138
} // namespace v1
128139
} // namespace stdx
129140

test/fail/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ add_fail_tests(
2525
to_address_undefined_on_function)
2626

2727
if(${CMAKE_CXX_STANDARD} GREATER_EQUAL 20)
28+
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang"
29+
AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL 15)
30+
add_fail_tests(ct_check)
31+
endif()
32+
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION}
33+
VERSION_GREATER_EQUAL 13.2)
34+
add_fail_tests(ct_check)
35+
endif()
36+
2837
add_fail_tests(
2938
dynamic_span_no_ct_capacity
3039
dynamic_container_no_ct_capacity

test/fail/ct_check.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <stdx/ct_string.hpp>
2+
3+
// EXPECT: 01234567890123456789012345678901234567890123456789
4+
5+
constexpr auto msg =
6+
stdx::ct_string{"01234567890123456789012345678901234567890123456789"};
7+
8+
auto main() -> int {
9+
stdx::ct_check<true>.emit<"not emitted">();
10+
stdx::ct_check<false>.emit<msg>();
11+
}

0 commit comments

Comments
 (0)