Skip to content

Commit e71580e

Browse files
authored
Merge pull request intel#141 from elbeno/compile-time-message
✨ Add compile-time diagnostic `ct_check`
2 parents 66f25a0 + 8b294fb commit e71580e

File tree

6 files changed

+73
-7
lines changed

6 files changed

+73
-7
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/compiler.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,10 @@
4343
#define LIFETIMEBOUND
4444
#endif
4545
#endif
46+
47+
#define STDX_DO_PRAGMA(X) _Pragma(#X)
48+
#ifdef __clang__
49+
#define STDX_PRAGMA(X) STDX_DO_PRAGMA(clang X)
50+
#else
51+
#define STDX_PRAGMA(X) STDX_DO_PRAGMA(GCC X)
52+
#endif

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

include/stdx/utility.hpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,6 @@ constexpr auto is_aligned_with = [](auto v) -> bool {
186186
#define FWD(x) std::forward<decltype(x)>(x)
187187
#endif
188188

189-
#define STDX_DO_PRAGMA(X) _Pragma(#X)
190-
#ifdef __clang__
191-
#define STDX_PRAGMA(X) STDX_DO_PRAGMA(clang X)
192-
#else
193-
#define STDX_PRAGMA(X) STDX_DO_PRAGMA(GCC X)
194-
#endif
195-
196189
#ifndef CX_VALUE
197190
#define CX_VALUE(...) \
198191
[] { \

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)