Optional Two-phase heap tracing
[hiphop-php.git] / hphp / util / assertions.h
blobf46dde7fa7ab932acab70a166e8ebee92c04709b
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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_
19 #include <cassert>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <exception>
23 #include <functional>
24 #include <string>
25 #include <type_traits>
26 #include <utility>
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() \
39 do { \
40 assert(false); \
41 } while (true)
42 #elif defined(_MSC_VER)
43 #define not_reached() __assume(0)
44 #else
45 #define not_reached() /* gcc-4.5 supports __builtin_unreachable() */ \
46 do { \
47 assert(false); \
48 __builtin_unreachable(); \
49 } while (true)
50 #endif
52 #define not_implemented() do { \
53 fprintf(stderr, "not implemented: %s:%d %s\n", \
54 __FILE__, __LINE__, __FUNCTION__); \
55 always_assert(0); \
56 } while (0)
58 #define assert_not_implemented(pred) do { \
59 if (! (pred) ) { \
60 not_implemented(); \
61 } \
62 } while(0)
64 namespace HPHP {
66 ///////////////////////////////////////////////////////////////////////////////
69 * Assertion abort and log functions.
71 * These are intended for use primarily by the assert macros below.
73 [[noreturn]]
74 void assert_fail(const char* e,
75 const char* file,
76 unsigned int line,
77 const char* func,
78 const std::string& msg);
80 [[noreturn]]
81 void assert_fail_no_log(const char* e,
82 const char* file,
83 unsigned int line,
84 const char* func,
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.
106 static bool log();
108 protected:
109 explicit AssertDetailImpl(const char* name)
110 : m_name(name)
111 , m_next(s_head)
113 #ifndef NDEBUG
114 if (m_name == nullptr) std::abort();
115 #endif
116 s_head = this;
118 ~AssertDetailImpl() { if (m_name) s_head = m_next; }
120 AssertDetailImpl(AssertDetailImpl&& other) noexcept {
121 #ifndef NDEBUG
122 if (s_head != &other) std::abort();
123 #endif
124 m_name = other.m_name;
125 m_next = other.m_next;
126 s_head = this;
127 other.m_name = nullptr; // prevents ~other from messing it up
130 AssertDetailImpl(const AssertDetailImpl&) = delete;
131 AssertDetailImpl& operator=(const AssertDetailImpl&) = delete;
133 private:
134 static bool log_impl(const AssertDetailImpl*);
135 virtual std::string run() const = 0;
137 private:
138 static __thread AssertDetailImpl* s_head;
140 const char* m_name;
141 AssertDetailImpl* m_next{nullptr};
144 template<class F>
145 struct AssertDetailT final : AssertDetailImpl {
146 AssertDetailT(const char* name, F&& f)
147 : AssertDetailImpl(name)
148 , m_f(std::move(f))
150 AssertDetailT(AssertDetailT&&) = default;
152 private:
153 std::string run() const override { return m_f(); }
155 private:
156 F m_f;
159 namespace detail {
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));
170 private:
171 const char* m_name;
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)))
185 #else
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); })
194 #endif
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()))
209 #undef assert
211 #ifndef NDEBUG
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__)
217 #else
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)
223 #endif
225 const bool do_assert =
226 #ifdef NDEBUG
227 false
228 #else
229 true
230 #endif
233 ///////////////////////////////////////////////////////////////////////////////
237 #endif