summaryrefslogtreecommitdiff
path: root/src/base/check.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/check.h')
-rw-r--r--src/base/check.h240
1 files changed, 240 insertions, 0 deletions
diff --git a/src/base/check.h b/src/base/check.h
new file mode 100644
index 000000000..915f6e4cb
--- /dev/null
+++ b/src/base/check.h
@@ -0,0 +1,240 @@
+/********************* */
+/*! \file check.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Assertion utility classes, functions and macros.
+ **
+ ** The AlwaysAssert utility classes, functions and macros.
+ **
+ ** The main usage in the file is the AlwaysAssert macros. The AlwaysAssert
+ ** macros assert a condition and aborts()'s the process if the condition is
+ ** not satisfied. The macro leaves a hanging ostream for the user to specify
+ ** additional information about the failure. Example usage:
+ ** AlwaysAssert(x >= 0) << "x must be positive.";
+ **
+ ** Assert is a AlwaysAssert that is only enabled in debug builds.
+ ** Assert(pointer != nullptr);
+ **
+ ** CVC4_FATAL() can be used to indicate unreachable code.
+ **
+ ** The AlwaysAssert and Assert macros are not safe for use in
+ ** signal-handling code. In future, a a signal-handling safe version of
+ ** AlwaysAssert may be added.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__CHECK_H
+#define CVC4__CHECK_H
+
+#include <cstdarg>
+#include <ostream>
+
+#include "base/exception.h"
+
+// Define CVC4_NO_RETURN macro replacement for [[noreturn]].
+#if defined(SWIG)
+#define CVC4_NO_RETURN
+// SWIG does not yet support [[noreturn]] so emit nothing instead.
+#else
+#define CVC4_NO_RETURN [[noreturn]]
+// Not checking for whether the compiler supports [[noreturn]] using
+// __has_cpp_attribute as GCC 4.8 is too widespread and does not support this.
+// We instead assume this is C++11 (or later) and [[noreturn]] is available.
+#endif // defined(SWIG)
+
+// Define CVC4_PREDICT_FALSE(x) that helps the compiler predict that x will be
+// false (if there is compiler support).
+#ifdef __has_builtin
+#if __has_builtin(__builtin_expect)
+#define CVC4_PREDICT_FALSE(x) (__builtin_expect(x, false))
+#define CVC4_PREDICT_TRUE(x) (__builtin_expect(x, true))
+#else
+#define CVC4_PREDICT_FALSE(x) x
+#define CVC4_PREDICT_TRUE(x) x
+#endif
+#else
+#define CVC4_PREDICT_FALSE(x) x
+#define CVC4_PREDICT_TRUE(x) x
+#endif
+
+namespace CVC4 {
+
+// Implementation notes:
+// To understand FatalStream and OStreamVoider, it is useful to understand
+// how a AlwaysAssert is structured. AlwaysAssert(cond) is roughly the following
+// pattern:
+// cond ? (void)0 : OstreamVoider() & FatalStream().stream()
+// This is a carefully crafted message to achieve a hanging ostream using
+// operator precedence. The line `AlwaysAssert(cond) << foo << bar;` will bind
+// as follows:
+// `cond ? ((void)0) : (OSV() & ((FS().stream() << foo) << bar));`
+// Once the expression is evaluated, the destructor ~FatalStream() of the
+// temporary object is then run, which abort()'s the process. The role of the
+// OStreamVoider() is to match the void type of the true branch.
+
+// Class that provides an ostream and whose destructor aborts! Direct usage of
+// this class is discouraged.
+class FatalStream
+{
+ public:
+ FatalStream(const char* function, const char* file, int line);
+ CVC4_NO_RETURN ~FatalStream();
+
+ std::ostream& stream();
+
+ private:
+ void Flush();
+};
+
+// Helper class that changes the type of an std::ostream& into a void. See
+// "Implementation notes" for more information.
+class OstreamVoider
+{
+ public:
+ OstreamVoider() {}
+ // The operator precedence between operator& and operator<< is critical here.
+ void operator&(std::ostream&) {}
+};
+
+// CVC4_FATAL() always aborts a function and provides a convenient way of
+// formatting error messages. This can be used instead of a return type.
+//
+// Example function that returns a type Foo:
+// Foo bar(T t) {
+// switch(t.type()) {
+// ...
+// default:
+// CVC4_FATAL() << "Unknown T type " << t.enum();
+// }
+// }
+#define CVC4_FATAL() \
+ FatalStream(__PRETTY_FUNCTION__, __FILE__, __LINE__).stream()
+
+/* GCC <= 9.2 ignores CVC4_NO_RETURN of ~FatalStream() if
+ * used in template classes (e.g., CDHashMap::save()). As a workaround we
+ * explicitly call abort() to let the compiler know that the
+ * corresponding function call will not return. */
+#define SuppressWrongNoReturnWarning abort()
+
+// If `cond` is true, log an error message and abort the process.
+// Otherwise, does nothing. This leaves a hanging std::ostream& that can be
+// inserted into.
+#define CVC4_FATAL_IF(cond, function, file, line) \
+ CVC4_PREDICT_FALSE(!(cond)) \
+ ? (void)0 : OstreamVoider() & FatalStream(function, file, line).stream()
+
+// If `cond` is false, log an error message and abort()'s the process.
+// Otherwise, does nothing. This leaves a hanging std::ostream& that can be
+// inserted into using operator<<. Example usages:
+// AlwaysAssert(x >= 0);
+// AlwaysAssert(x >= 0) << "x must be positive";
+// AlwaysAssert(x >= 0) << "expected a positive value. Got " << x << "
+// instead";
+#define AlwaysAssert(cond) \
+ CVC4_FATAL_IF(!(cond), __PRETTY_FUNCTION__, __FILE__, __LINE__) \
+ << "Check failure\n\n " << #cond << "\n"
+
+// Assert is a variant of AlwaysAssert() that is only checked when
+// CVC4_ASSERTIONS is defined. We rely on the optimizer to remove the deadcode.
+#ifdef CVC4_ASSERTIONS
+#define Assert(cond) AlwaysAssert(cond)
+#else
+#define Assert(cond) \
+ CVC4_FATAL_IF(false, __PRETTY_FUNCTION__, __FILE__, __LINE__)
+#endif /* CVC4_DEBUG */
+
+class AssertArgumentException : public Exception
+{
+ protected:
+ AssertArgumentException() : Exception() {}
+
+ void construct(const char* header,
+ const char* extra,
+ const char* function,
+ const char* file,
+ unsigned line,
+ const char* fmt,
+ va_list args);
+
+ void construct(const char* header,
+ const char* extra,
+ const char* function,
+ const char* file,
+ unsigned line);
+
+ public:
+ AssertArgumentException(const char* condStr,
+ const char* argDesc,
+ const char* function,
+ const char* file,
+ unsigned line,
+ const char* fmt,
+ ...);
+
+ AssertArgumentException(const char* condStr,
+ const char* argDesc,
+ const char* function,
+ const char* file,
+ unsigned line);
+
+}; /* class AssertArgumentException */
+
+#define Unreachable() CVC4_FATAL() << "Unreachable code reached"
+
+#define Unhandled() CVC4_FATAL() << "Unhandled case encountered"
+
+#define Unimplemented() CVC4_FATAL() << "Unimplemented code encountered"
+
+#define InternalError() CVC4_FATAL() << "Internal error detected"
+
+#define IllegalArgument(arg, msg...) \
+ throw ::CVC4::IllegalArgumentException( \
+ "", \
+ #arg, \
+ __PRETTY_FUNCTION__, \
+ ::CVC4::IllegalArgumentException::formatVariadic(msg).c_str());
+// This cannot use check argument directly as this forces
+// CheckArgument to use a va_list. This is unsupported in Swig.
+#define PrettyCheckArgument(cond, arg, msg...) \
+ do \
+ { \
+ if (__builtin_expect((!(cond)), false)) \
+ { \
+ throw ::CVC4::IllegalArgumentException( \
+ #cond, \
+ #arg, \
+ __PRETTY_FUNCTION__, \
+ ::CVC4::IllegalArgumentException::formatVariadic(msg).c_str()); \
+ } \
+ } while (0)
+#define AlwaysAssertArgument(cond, arg, msg...) \
+ do \
+ { \
+ if (__builtin_expect((!(cond)), false)) \
+ { \
+ throw ::CVC4::AssertArgumentException( \
+ #cond, #arg, __PRETTY_FUNCTION__, __FILE__, __LINE__, ##msg); \
+ } \
+ } while (0)
+
+#ifdef CVC4_ASSERTIONS
+#define AssertArgument(cond, arg, msg...) AlwaysAssertArgument(cond, arg, ##msg)
+#define DebugCheckArgument(cond, arg, msg...) CheckArgument(cond, arg, ##msg)
+#else /* ! CVC4_ASSERTIONS */
+#define AssertArgument(cond, arg, msg...) /*__builtin_expect( ( cond ), true \
+ )*/
+#define DebugCheckArgument( \
+ cond, arg, msg...) /*__builtin_expect( ( cond ), true )*/
+#endif /* CVC4_ASSERTIONS */
+
+} // namespace CVC4
+
+#endif /* CVC4__CHECK_H */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback