Skip to content

Commit 12b3982

Browse files
committed
Add bitfield support
1 parent 6db8c48 commit 12b3982

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

include/libassert/assert-macros.hpp

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,48 @@
55
// https://github.com/jeremy-rifkin/libassert
66

77
#include <libassert/platform.hpp>
8-
8+
#include <libassert/expression-decomposition.hpp>
99
#include <string_view>
1010

11+
LIBASSERT_BEGIN_NAMESPACE
12+
namespace detail {
13+
14+
template <typename Concept, typename = void>
15+
inline constexpr bool is_referencable_expression_impl = false;
16+
17+
template <typename Concept>
18+
inline constexpr bool is_referencable_expression_impl<
19+
Concept,
20+
decltype(void(std::declval<Concept>()(detail::expression_decomposer{})))> = true;
21+
22+
template <typename Concept>
23+
constexpr bool is_referencable_expression(const Concept&) {
24+
return is_referencable_expression_impl<Concept>;
25+
}
26+
// A macro that checks whether an expression can be decomposed by the
27+
// decomposer. An expression that fails is a bitfield for example.
28+
#define LIBASSERT_IS_DECOMPOSABLE_EXPR(expr) \
29+
libassert::detail::is_referencable_expression( \
30+
[](auto expr_decomposer) -> decltype(std::move(expr_decomposer) \
31+
<< expr) {})
32+
33+
// The decomposer is passed as a template parameter to not evaluate the other
34+
// path and cause a hard error
35+
#define LIBASSERT_DECOMPOSER(expr) \
36+
[&](auto decomposer) { \
37+
if constexpr (sizeof(decomposer) && \
38+
LIBASSERT_IS_DECOMPOSABLE_EXPR(expr)) { \
39+
return libassert::detail::expression_decomposer(std::move(decomposer) \
40+
<< expr); \
41+
} else { \
42+
return std::move(decomposer) << (expr); \
43+
} \
44+
}(libassert::detail::expression_decomposer{})
45+
46+
} // namespace detail
47+
LIBASSERT_END_NAMESPACE
48+
49+
1150
#if LIBASSERT_IS_CLANG || LIBASSERT_IS_GCC || !LIBASSERT_NON_CONFORMANT_MSVC_PREPROCESSOR
1251
// Macro mapping utility by William Swanson https://github.com/swansontec/map-macro/blob/master/map.h
1352
#define LIBASSERT_EVAL0(...) __VA_ARGS__
@@ -208,9 +247,7 @@ LIBASSERT_END_NAMESPACE
208247
if constexpr(false) { (void)(expr);} \
209248
LIBASSERT_WARNING_PRAGMA_PUSH \
210249
LIBASSERT_EXPRESSION_DECOMP_WARNING_PRAGMA \
211-
auto libassert_decomposer = libassert::detail::expression_decomposer( \
212-
libassert::detail::expression_decomposer{} << expr \
213-
); \
250+
auto libassert_decomposer = LIBASSERT_DECOMPOSER(expr);\
214251
LIBASSERT_WARNING_PRAGMA_POP \
215252
LIBASSERT_ASSERT_MAIN_BODY( \
216253
expr, \

tests/unit/assertion_tests.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,26 @@ TEST(LibassertBasic, NULLMacroComparison) {
275275
);
276276
}
277277

278+
TEST(LibassertBasic, Bitfields) {
279+
struct Bit {
280+
int bit : 1;
281+
};
282+
Bit bit{1};
283+
CHECK(
284+
ASSERT(bit.bit == 1),
285+
R"XX(
286+
|Assertion failed at <LOCATION>:
287+
| ASSERT(bit.bit == 1);
288+
)XX"
289+
);
290+
291+
CHECK(ASSERT(1 == bit.bit),
292+
R"XX(
293+
|Assertion failed at <LOCATION>:
294+
| ASSERT(1 == bit.bit);
295+
)XX");
296+
}
297+
278298

279299
TEST(LibassertBasic, LiteralFormatting) {
280300
const uint16_t flags = 0b000101010;
@@ -599,13 +619,15 @@ TEST(LibassertBasic, General) {
599619
| printable{2.55} => (printable = 2.55)
600620
)XX"
601621
);
622+
#if LIBASSERT_CPLUSPLUS >= 202002
602623
CHECK(
603624
ASSERT([] { return false; } ()),
604625
R"XX(
605626
|Assertion failed at <LOCATION>:
606627
| ASSERT([] { return false; } ());
607628
)XX"
608629
);
630+
#endif
609631
}
610632

611633
TEST(LibassertBasic, SignedUnsignedComparisonWithoutSafeCompareMode) {
@@ -700,6 +722,7 @@ TEST(LibassertBasic, ExpressionDecomposition) {
700722
| x -= x -= 1 => 0
701723
)XX"
702724
);
725+
703726
CHECK(
704727
ASSERT(true ? false : true, "pffft"),
705728
R"XX(

0 commit comments

Comments
 (0)