Skip to content

Commit 2ef47ba

Browse files
committed
util/check: stop using lambda for Assert/Assume
1 parent 7c9fe25 commit 2ef47ba

File tree

4 files changed

+65
-8
lines changed

4 files changed

+65
-8
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ libbitcoin_util_a_SOURCES = \
621621
util/asmap.cpp \
622622
util/bip32.cpp \
623623
util/bytevectorhash.cpp \
624+
util/check.cpp \
624625
util/error.cpp \
625626
util/fees.cpp \
626627
util/getuniquepath.cpp \
@@ -839,6 +840,7 @@ bitcoin_chainstate_SOURCES = \
839840
uint256.cpp \
840841
util/asmap.cpp \
841842
util/bytevectorhash.cpp \
843+
util/check.cpp \
842844
util/getuniquepath.cpp \
843845
util/hasher.cpp \
844846
util/moneystr.cpp \

src/test/util_tests.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,31 @@ BOOST_AUTO_TEST_CASE(util_datadir)
7878
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
7979
}
8080

81+
namespace {
82+
class NoCopyOrMove
83+
{
84+
public:
85+
int i;
86+
explicit NoCopyOrMove(int i) : i{i} { }
87+
88+
NoCopyOrMove() = delete;
89+
NoCopyOrMove(const NoCopyOrMove&) = delete;
90+
NoCopyOrMove(NoCopyOrMove&&) = delete;
91+
NoCopyOrMove& operator=(const NoCopyOrMove&) = delete;
92+
NoCopyOrMove& operator=(NoCopyOrMove&&) = delete;
93+
94+
operator bool() const { return i != 0; }
95+
96+
int get_ip1() { return i + 1; }
97+
bool test()
98+
{
99+
// Check that Assume can be used within a lambda and still call methods
100+
[&]() { Assume(get_ip1()); }();
101+
return Assume(get_ip1() != 5);
102+
}
103+
};
104+
} // namespace
105+
81106
BOOST_AUTO_TEST_CASE(util_check)
82107
{
83108
// Check that Assert can forward
@@ -89,6 +114,14 @@ BOOST_AUTO_TEST_CASE(util_check)
89114
// Check that Assume can be used as unary expression
90115
const bool result{Assume(two == 2)};
91116
Assert(result);
117+
118+
// Check that Assert doesn't require copy/move
119+
NoCopyOrMove x{9};
120+
Assert(x).i += 3;
121+
Assert(x).test();
122+
123+
// Check nested Asserts
124+
BOOST_CHECK_EQUAL(Assert((Assert(x).test() ? 3 : 0)), 3);
92125
}
93126

94127
BOOST_AUTO_TEST_CASE(util_criticalsection)

src/util/check.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <util/check.h>
6+
7+
#include <tinyformat.h>
8+
9+
void assertion_fail(const char* file, int line, const char* func, const char* assertion)
10+
{
11+
auto str = strprintf("%s:%s %s: Assertion `%s' failed.\n", file, line, func, assertion);
12+
fwrite(str.data(), 1, str.size(), stderr);
13+
std::abort();
14+
}

src/util/check.h

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,26 @@ class NonFatalCheckError : public std::runtime_error
4747
#endif
4848

4949
/** Helper for Assert() */
50-
template <typename T>
51-
T get_pure_r_value(T&& val)
50+
void assertion_fail(const char* file, int line, const char* func, const char* assertion);
51+
52+
/** Helper for Assert()/Assume() */
53+
template <bool IS_ASSERT, typename T>
54+
T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion)
5255
{
56+
if constexpr (IS_ASSERT
57+
#ifdef ABORT_ON_FAILED_ASSUME
58+
|| true
59+
#endif
60+
) {
61+
if (!val) {
62+
assertion_fail(file, line, func, assertion);
63+
}
64+
}
5365
return std::forward<T>(val);
5466
}
5567

5668
/** Identity function. Abort if the value compares equal to zero */
57-
#define Assert(val) ([&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); assert(#val && check); return std::forward<decltype(get_pure_r_value(val))>(check); }())
69+
#define Assert(val) inline_assertion_check<true>(val, __FILE__, __LINE__, __func__, #val)
5870

5971
/**
6072
* Assume is the identity function.
@@ -66,10 +78,6 @@ T get_pure_r_value(T&& val)
6678
* - For non-fatal errors in interactive sessions (e.g. RPC or command line
6779
* interfaces), CHECK_NONFATAL() might be more appropriate.
6880
*/
69-
#ifdef ABORT_ON_FAILED_ASSUME
70-
#define Assume(val) Assert(val)
71-
#else
72-
#define Assume(val) ([&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); return std::forward<decltype(get_pure_r_value(val))>(check); }())
73-
#endif
81+
#define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val)
7482

7583
#endif // BITCOIN_UTIL_CHECK_H

0 commit comments

Comments
 (0)