no unique F14Chunk empty-tag-vector instance
[hiphop-php.git] / hphp / util / assertions.h
blob15562c6e9ab88dcca50f048fbd90bb9062cbd4ad
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 #pragma once
18 #include <cassert>
19 #include <cstdio>
20 #include <cstdlib>
21 #include <exception>
22 #include <functional>
23 #include <string>
24 #include <type_traits>
25 #include <utility>
27 #include <folly/Format.h>
28 #include <folly/Preprocessor.h>
30 #include "hphp/util/portability.h"
32 ///////////////////////////////////////////////////////////////////////////////
34 #define IMPLIES(a, b) (!(a) || (b))
36 #define not_reached() /* gcc-4.5 supports __builtin_unreachable() */ \
37 do { \
38 assertx(false); \
39 __builtin_unreachable(); \
40 } while (true)
42 #define not_implemented() do { \
43 fprintf(stderr, "not implemented: %s:%d %s\n", \
44 __FILE__, __LINE__, __FUNCTION__); \
45 always_assert(0); \
46 } while (0)
48 #define assert_not_implemented(pred) do { \
49 if (! (pred) ) { \
50 not_implemented(); \
51 } \
52 } while(0)
54 namespace HPHP {
56 ///////////////////////////////////////////////////////////////////////////////
59 * Assertion abort and log functions.
61 * These are intended for use primarily by the assert macros below.
63 [[noreturn]]
64 void assert_fail(const char* e,
65 const char* file,
66 unsigned int line,
67 const char* func,
68 const std::string& msg);
70 ///////////////////////////////////////////////////////////////////////////////
73 * Stack-allocated detailed assertion logger.
75 struct AssertDetailImpl {
77 * Reads the most recently added message, and removes it from the
78 * list. Returns true if there was a message to read.
80 static bool readAndRemove(std::string& msg);
81 protected:
82 explicit AssertDetailImpl(const char* name)
83 : m_name(name)
84 , m_next(s_head)
86 #ifndef NDEBUG
87 if (m_name == nullptr) std::abort();
88 #endif
89 s_head = this;
91 ~AssertDetailImpl() { if (m_name) s_head = m_next; }
93 AssertDetailImpl(AssertDetailImpl&& other) noexcept {
94 #ifndef NDEBUG
95 if (s_head != &other) std::abort();
96 #endif
97 m_name = other.m_name;
98 m_next = other.m_next;
99 s_head = this;
100 other.m_name = nullptr; // prevents ~other from messing it up
103 AssertDetailImpl(const AssertDetailImpl&) = delete;
104 AssertDetailImpl& operator=(const AssertDetailImpl&) = delete;
106 private:
107 static std::pair<std::string,std::string>
108 log_one(const AssertDetailImpl* adi, const char* name);
109 virtual std::string run() const = 0;
111 private:
112 static __thread AssertDetailImpl* s_head;
114 const char* m_name;
115 AssertDetailImpl* m_next{nullptr};
118 template<class F>
119 struct AssertDetailT final : AssertDetailImpl {
120 AssertDetailT(const char* name, F&& f)
121 : AssertDetailImpl(name)
122 , m_f(std::move(f))
124 AssertDetailT(AssertDetailT&&) = default;
126 private:
127 std::string run() const override { return m_f(); }
129 private:
130 F m_f;
133 namespace detail {
135 struct AssertDetailScopeMaker {
136 explicit AssertDetailScopeMaker(const char* name) : m_name(name) {}
138 template <typename F>
139 AssertDetailT<typename std::decay<F>::type> operator+(F&& f) {
140 return AssertDetailT<typename std::decay<F>::type>(
141 m_name, std::forward<F>(f));
144 private:
145 const char* m_name;
150 #define SCOPE_ASSERT_DETAIL(name) \
151 auto const FB_ANONYMOUS_VARIABLE(SCOPE_ASSERT) \
152 = ::HPHP::detail::AssertDetailScopeMaker(name) + [&]()
154 ///////////////////////////////////////////////////////////////////////////////
156 # if !defined __GNUC__ || defined __STRICT_ANSI__
157 #define assert_impl(cond, fail) \
158 ((cond) ? static_cast<void>(0) : ((fail), static_cast<void>(0)))
159 #else
161 * This is preferred, because "cond" is not over-parenthesized, and
162 * thus -Wparentheses can warn about errors like "always_assert(a=1)".
163 * With -pedantic, we cannot use "({...})" statement expressions,
164 * so must resort to the old way, above.
166 #define assert_impl(cond, fail) \
167 ({ if (cond) ; else { fail; } static_cast<void>(0); })
168 #endif
170 #define assert_fail_impl(e, msg) \
171 ::HPHP::assert_fail(#e, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg)
173 #define always_assert(e) assert_impl(e, assert_fail_impl(e, ""))
174 #define always_assert_log(e, l) assert_impl(e, assert_fail_impl(e, l()))
175 #define always_assert_flog(e, ...) assert_impl(e, assert_fail_impl(e, \
176 ::folly::format(__VA_ARGS__).str()))
178 #undef assert
180 #ifndef NDEBUG
181 #define assert(e) always_assert(e)
182 #define assertx(e) always_assert(e)
183 #define assert_log(e, l) always_assert_log(e, l)
184 #define assert_flog(e, ...) always_assert_flog(e, __VA_ARGS__)
185 #else
186 #define assert(e) static_cast<void>(0)
187 #define assertx(e) static_cast<void>(0)
188 #define assert_log(e, l) static_cast<void>(0)
189 #define assert_flog(e, ...) static_cast<void>(0)
190 #endif
192 ///////////////////////////////////////////////////////////////////////////////