2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_ASSERTIONS_H_
17 #define incl_HPHP_ASSERTIONS_H_
25 #include <type_traits>
28 #include <folly/Format.h>
29 #include <folly/Preprocessor.h>
31 #include "hphp/util/portability.h"
33 ///////////////////////////////////////////////////////////////////////////////
35 #define IMPLIES(a, b) (!(a) || (b))
37 #if defined(__INTEL_COMPILER)
38 #define not_reached() \
42 #elif defined(_MSC_VER)
43 #define not_reached() __assume(0)
45 #define not_reached() /* gcc-4.5 supports __builtin_unreachable() */ \
48 __builtin_unreachable(); \
52 #define not_implemented() do { \
53 fprintf(stderr, "not implemented: %s:%d %s\n", \
54 __FILE__, __LINE__, __FUNCTION__); \
58 #define assert_not_implemented(pred) do { \
66 ///////////////////////////////////////////////////////////////////////////////
69 * Assertion abort and log functions.
71 * These are intended for use primarily by the assert macros below.
74 void assert_fail(const char* e
,
78 const std::string
& msg
);
81 void assert_fail_no_log(const char* e
,
85 const std::string
& msg
);
87 void assert_log_failure(const char* title
, const std::string
& msg
);
90 * Register a function for auxiliary assert logging.
92 using AssertFailLogger
= std::function
<void(const char*, const std::string
&)>;
94 void register_assert_fail_logger(AssertFailLogger
);
96 ///////////////////////////////////////////////////////////////////////////////
99 * Stack-allocated detailed assertion logger.
101 struct AssertDetailImpl
{
103 * Prints the results of all registered detailers to stderr. Returns true if
104 * we had any registered detailers.
109 explicit AssertDetailImpl(const char* name
)
114 if (m_name
== nullptr) std::abort();
118 ~AssertDetailImpl() { if (m_name
) s_head
= m_next
; }
120 AssertDetailImpl(AssertDetailImpl
&& other
) noexcept
{
122 if (s_head
!= &other
) std::abort();
124 m_name
= other
.m_name
;
125 m_next
= other
.m_next
;
127 other
.m_name
= nullptr; // prevents ~other from messing it up
130 AssertDetailImpl(const AssertDetailImpl
&) = delete;
131 AssertDetailImpl
& operator=(const AssertDetailImpl
&) = delete;
134 static bool log_impl(const AssertDetailImpl
*);
135 virtual std::string
run() const = 0;
138 static __thread AssertDetailImpl
* s_head
;
141 AssertDetailImpl
* m_next
{nullptr};
145 struct AssertDetailT final
: AssertDetailImpl
{
146 AssertDetailT(const char* name
, F
&& f
)
147 : AssertDetailImpl(name
)
150 AssertDetailT(AssertDetailT
&&) = default;
153 std::string
run() const override
{ return m_f(); }
161 struct AssertDetailScopeMaker
{
162 explicit AssertDetailScopeMaker(const char* name
) : m_name(name
) {}
164 template <typename F
>
165 AssertDetailT
<typename
std::decay
<F
>::type
> operator+(F
&& f
) {
166 return AssertDetailT
<typename
std::decay
<F
>::type
>(
167 m_name
, std::forward
<F
>(f
));
176 #define SCOPE_ASSERT_DETAIL(name) \
177 auto FB_ANONYMOUS_VARIABLE(SCOPE_ASSERT) \
178 = ::HPHP::detail::AssertDetailScopeMaker(name) + [&]()
180 ///////////////////////////////////////////////////////////////////////////////
182 # if !defined __GNUC__ || defined __STRICT_ANSI__
183 #define assert_impl(cond, fail) \
184 ((cond) ? static_cast<void>(0) : ((fail), static_cast<void>(0)))
187 * This is preferred, because "cond" is not over-parenthesized, and
188 * thus -Wparentheses can warn about errors like "always_assert(a=1)".
189 * With -pedantic, we cannot use "({...})" statement expressions,
190 * so must resort to the old way, above.
192 #define assert_impl(cond, fail) \
193 ({ if (cond) ; else { fail; } static_cast<void>(0); })
196 #define assert_fail_impl(e, msg) \
197 ::HPHP::assert_fail(#e, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg)
199 #define assert_fail_impl_no_log(e, msg) \
200 ::HPHP::assert_fail_no_log(#e, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg)
202 #define always_assert(e) assert_impl(e, assert_fail_impl(e, ""))
203 #define always_assert_no_log(e) assert_impl(e, \
204 assert_fail_impl_no_log(e, ""))
205 #define always_assert_log(e, l) assert_impl(e, assert_fail_impl(e, l()))
206 #define always_assert_flog(e, ...) assert_impl(e, assert_fail_impl(e, \
207 ::folly::format(__VA_ARGS__).str()))
212 #define assert(e) always_assert(e)
213 #define assertx(e) always_assert(e)
214 #define assert_no_log(e) always_assert_no_log(e)
215 #define assert_log(e, l) always_assert_log(e, l)
216 #define assert_flog(e, ...) always_assert_flog(e, __VA_ARGS__)
218 #define assert(e) static_cast<void>(0)
219 #define assertx(e) static_cast<void>(0)
220 #define assert_no_log(e) static_cast<void>(0)
221 #define assert_log(e, l) static_cast<void>(0)
222 #define assert_flog(e, ...) static_cast<void>(0)
225 const bool do_assert
=
233 ///////////////////////////////////////////////////////////////////////////////