GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/base/check.h Lines: 3 3 100.0 %
Date: 2021-03-22 Branches: 0 0 0.0 %

Line Exec Source
1
/*********************                                                        */
2
/*! \file check.h
3
 ** \verbatim
4
 ** Top contributors (to current version):
5
 **   Mathias Preiner, Tim King, Andres Noetzli
6
 ** This file is part of the CVC4 project.
7
 ** Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 ** in the top-level source directory and their institutional affiliations.
9
 ** All rights reserved.  See the file COPYING in the top-level source
10
 ** directory for licensing information.\endverbatim
11
 **
12
 ** \brief Assertion utility classes, functions and macros.
13
 **
14
 ** The AlwaysAssert utility classes, functions and macros.
15
 **
16
 ** The main usage in the file is the AlwaysAssert macros. The AlwaysAssert
17
 ** macros assert a condition and aborts()'s the process if the condition is
18
 ** not satisfied. The macro leaves a hanging ostream for the user to specify
19
 ** additional information about the failure. Example usage:
20
 **   AlwaysAssert(x >= 0) << "x must be positive.";
21
 **
22
 ** Assert is a AlwaysAssert that is only enabled in debug builds.
23
 **   Assert(pointer != nullptr);
24
 **
25
 ** CVC4_FATAL() can be used to indicate unreachable code.
26
 **
27
 ** The AlwaysAssert and Assert macros are not safe for use in
28
 ** signal-handling code. In future, a a signal-handling safe version of
29
 ** AlwaysAssert may be added.
30
 **/
31
32
#include "cvc4_private_library.h"
33
34
#ifndef CVC4__CHECK_H
35
#define CVC4__CHECK_H
36
37
#include <cstdarg>
38
#include <ostream>
39
40
#include "base/exception.h"
41
#include "cvc4_export.h"
42
43
// Define CVC4_NO_RETURN macro replacement for [[noreturn]].
44
#if defined(SWIG)
45
#define CVC4_NO_RETURN
46
// SWIG does not yet support [[noreturn]] so emit nothing instead.
47
#else
48
#define CVC4_NO_RETURN [[noreturn]]
49
// Not checking for whether the compiler supports [[noreturn]] using
50
// __has_cpp_attribute as GCC 4.8 is too widespread and does not support this.
51
// We instead assume this is C++11 (or later) and [[noreturn]] is available.
52
#endif  // defined(SWIG)
53
54
// Define CVC4_PREDICT_FALSE(x) that helps the compiler predict that x will be
55
// false (if there is compiler support).
56
#ifdef __has_builtin
57
#if __has_builtin(__builtin_expect)
58
#define CVC4_PREDICT_FALSE(x) (__builtin_expect(x, false))
59
#define CVC4_PREDICT_TRUE(x) (__builtin_expect(x, true))
60
#else
61
#define CVC4_PREDICT_FALSE(x) x
62
#define CVC4_PREDICT_TRUE(x) x
63
#endif
64
#else
65
#define CVC4_PREDICT_FALSE(x) x
66
#define CVC4_PREDICT_TRUE(x) x
67
#endif
68
69
#ifdef __has_cpp_attribute
70
#if __has_cpp_attribute(fallthrough)
71
#define CVC4_FALLTHROUGH [[fallthrough]]
72
#endif // __has_cpp_attribute(fallthrough)
73
#endif // __has_cpp_attribute
74
#ifndef CVC4_FALLTHROUGH
75
#define CVC4_FALLTHROUGH
76
#endif
77
78
namespace CVC4 {
79
80
// Implementation notes:
81
// To understand FatalStream and OStreamVoider, it is useful to understand
82
// how a AlwaysAssert is structured. AlwaysAssert(cond) is roughly the following
83
// pattern:
84
//  cond ? (void)0 : OstreamVoider() & FatalStream().stream()
85
// This is a carefully crafted message to achieve a hanging ostream using
86
// operator precedence. The line `AlwaysAssert(cond) << foo << bar;` will bind
87
// as follows:
88
//  `cond ? ((void)0) : (OSV() & ((FS().stream() << foo) << bar));`
89
// Once the expression is evaluated, the destructor ~FatalStream() of the
90
// temporary object is then run, which abort()'s the process. The role of the
91
// OStreamVoider() is to match the void type of the true branch.
92
93
// Class that provides an ostream and whose destructor aborts! Direct usage of
94
// this class is discouraged.
95
class CVC4_EXPORT FatalStream
96
{
97
 public:
98
  FatalStream(const char* function, const char* file, int line);
99
  CVC4_NO_RETURN ~FatalStream();
100
101
  std::ostream& stream();
102
103
 private:
104
  void Flush();
105
};
106
107
// Helper class that changes the type of an std::ostream& into a void. See
108
// "Implementation notes" for more information.
109
class OstreamVoider
110
{
111
 public:
112
796
  OstreamVoider() {}
113
  // The operator precedence between operator& and operator<< is critical here.
114
796
  void operator&(std::ostream&) {}
115
};
116
117
// CVC4_FATAL() always aborts a function and provides a convenient way of
118
// formatting error messages. This can be used instead of a return type.
119
//
120
// Example function that returns a type Foo:
121
//   Foo bar(T t) {
122
//     switch(t.type()) {
123
//     ...
124
//     default:
125
//       CVC4_FATAL() << "Unknown T type " << t.enum();
126
//     }
127
//   }
128
#define CVC4_FATAL() \
129
  FatalStream(__PRETTY_FUNCTION__, __FILE__, __LINE__).stream()
130
131
/* GCC <= 9.2 ignores CVC4_NO_RETURN of ~FatalStream() if
132
 * used in template classes (e.g., CDHashMap::save()).  As a workaround we
133
 * explicitly call abort() to let the compiler know that the
134
 * corresponding function call will not return. */
135
#define SuppressWrongNoReturnWarning abort()
136
137
// If `cond` is true, log an error message and abort the process.
138
// Otherwise, does nothing. This leaves a hanging std::ostream& that can be
139
// inserted into.
140
#define CVC4_FATAL_IF(cond, function, file, line) \
141
  CVC4_PREDICT_FALSE(!(cond))                     \
142
  ? (void)0 : OstreamVoider() & FatalStream(function, file, line).stream()
143
144
// If `cond` is false, log an error message and abort()'s the process.
145
// Otherwise, does nothing. This leaves a hanging std::ostream& that can be
146
// inserted into using operator<<. Example usages:
147
//   AlwaysAssert(x >= 0);
148
//   AlwaysAssert(x >= 0) << "x must be positive";
149
//   AlwaysAssert(x >= 0) << "expected a positive value. Got " << x << "
150
//   instead";
151
#define AlwaysAssert(cond)                                        \
152
  CVC4_FATAL_IF(!(cond), __PRETTY_FUNCTION__, __FILE__, __LINE__) \
153
      << "Check failure\n\n " << #cond << "\n"
154
155
// Assert is a variant of AlwaysAssert() that is only checked when
156
// CVC4_ASSERTIONS is defined. We rely on the optimizer to remove the deadcode.
157
#ifdef CVC4_ASSERTIONS
158
#define Assert(cond) AlwaysAssert(cond)
159
#else
160
#define Assert(cond) \
161
  CVC4_FATAL_IF(false, __PRETTY_FUNCTION__, __FILE__, __LINE__)
162
#endif
163
164
14
class AssertArgumentException : public Exception
165
{
166
 protected:
167
  AssertArgumentException() : Exception() {}
168
169
  void construct(const char* header,
170
                 const char* extra,
171
                 const char* function,
172
                 const char* file,
173
                 unsigned line,
174
                 const char* fmt,
175
                 va_list args);
176
177
  void construct(const char* header,
178
                 const char* extra,
179
                 const char* function,
180
                 const char* file,
181
                 unsigned line);
182
183
 public:
184
  AssertArgumentException(const char* condStr,
185
                          const char* argDesc,
186
                          const char* function,
187
                          const char* file,
188
                          unsigned line,
189
                          const char* fmt,
190
                          ...);
191
192
  AssertArgumentException(const char* condStr,
193
                          const char* argDesc,
194
                          const char* function,
195
                          const char* file,
196
                          unsigned line);
197
198
}; /* class AssertArgumentException */
199
200
#define Unreachable() CVC4_FATAL() << "Unreachable code reached"
201
202
#define Unhandled() CVC4_FATAL() << "Unhandled case encountered"
203
204
#define Unimplemented() CVC4_FATAL() << "Unimplemented code encountered"
205
206
#define InternalError() CVC4_FATAL() << "Internal error detected"
207
208
#define IllegalArgument(arg, msg...)      \
209
  throw ::CVC4::IllegalArgumentException( \
210
      "",                                 \
211
      #arg,                               \
212
      __PRETTY_FUNCTION__,                \
213
      ::CVC4::IllegalArgumentException::formatVariadic(msg).c_str());
214
// This cannot use check argument directly as this forces
215
// CheckArgument to use a va_list. This is unsupported in Swig.
216
#define PrettyCheckArgument(cond, arg, msg...)                            \
217
  do                                                                      \
218
  {                                                                       \
219
    if (__builtin_expect((!(cond)), false))                               \
220
    {                                                                     \
221
      throw ::CVC4::IllegalArgumentException(                             \
222
          #cond,                                                          \
223
          #arg,                                                           \
224
          __PRETTY_FUNCTION__,                                            \
225
          ::CVC4::IllegalArgumentException::formatVariadic(msg).c_str()); \
226
    }                                                                     \
227
  } while (0)
228
#define AlwaysAssertArgument(cond, arg, msg...)                         \
229
  do                                                                    \
230
  {                                                                     \
231
    if (__builtin_expect((!(cond)), false))                             \
232
    {                                                                   \
233
      throw ::CVC4::AssertArgumentException(                            \
234
          #cond, #arg, __PRETTY_FUNCTION__, __FILE__, __LINE__, ##msg); \
235
    }                                                                   \
236
  } while (0)
237
238
#ifdef CVC4_ASSERTIONS
239
#define AssertArgument(cond, arg, msg...) AlwaysAssertArgument(cond, arg, ##msg)
240
#define DebugCheckArgument(cond, arg, msg...) CheckArgument(cond, arg, ##msg)
241
#else                                     /* ! CVC4_ASSERTIONS */
242
#define AssertArgument(cond, arg, msg...) /*__builtin_expect( ( cond ), true \
243
                                             )*/
244
#define DebugCheckArgument( \
245
    cond, arg, msg...) /*__builtin_expect( ( cond ), true )*/
246
#endif                 /* CVC4_ASSERTIONS */
247
248
}  // namespace CVC4
249
250
#endif /* CVC4__CHECK_H */