72
72
// / family of macros, allowing constructs like
73
73
// / `INVARIANT(x==y, my_invariantt, (T1)actual1, (T2)actual2, ...)`
74
74
// /
75
- class invariant_failedt : public std ::logic_error
75
+ class invariant_failedt
76
76
{
77
77
private:
78
- std::string get_invariant_failed_message (
79
- const std::string &file,
80
- const std::string &function,
81
- int line,
82
- const std::string &backtrace,
83
- const std::string &reason);
84
-
85
- public:
86
78
const std::string file;
87
79
const std::string function;
88
80
const int line;
89
81
const std::string backtrace;
82
+ const std::string condition;
90
83
const std::string reason;
91
84
85
+ public:
86
+ std::string what () const noexcept ;
87
+
92
88
invariant_failedt (
93
89
const std::string &_file,
94
90
const std::string &_function,
95
91
int _line,
96
92
const std::string &_backtrace,
97
- const std::string &_reason):
98
- logic_error (
99
- get_invariant_failed_message (
100
- _file,
101
- _function,
102
- _line,
103
- _backtrace,
104
- _reason)),
105
- file(_file),
106
- function(_function),
107
- line(_line),
108
- backtrace(_backtrace),
109
- reason(_reason)
93
+ const std::string &_condition,
94
+ const std::string &_reason)
95
+ : file(_file),
96
+ function (_function),
97
+ line(_line),
98
+ backtrace(_backtrace),
99
+ condition(_condition),
100
+ reason(_reason)
110
101
{
111
102
}
112
103
};
@@ -149,9 +140,10 @@ void report_exception_to_stderr(const invariant_failedt &);
149
140
// / \param file : C string giving the name of the file.
150
141
// / \param function : C string giving the name of the function.
151
142
// / \param line : The line number of the invariant
143
+ // / \param condition : the condition this invariant is checking.
152
144
// / \param params : (variadic) parameters to forward to ET's constructor
153
145
// / its backtrace member will be set before it is used.
154
- template <class ET , typename ...Params>
146
+ template <class ET , typename ... Params>
155
147
#ifdef __GNUC__
156
148
__attribute__ ((noreturn))
157
149
#endif
@@ -160,10 +152,17 @@ invariant_violated_structured(
160
152
const std::string &file,
161
153
const std::string &function,
162
154
const int line,
155
+ const std::string &condition,
163
156
Params &&... params)
164
157
{
165
158
std::string backtrace=get_backtrace ();
166
- ET to_throw (file, function, line, backtrace, std::forward<Params>(params)...);
159
+ ET to_throw (
160
+ file,
161
+ function,
162
+ line,
163
+ backtrace,
164
+ condition,
165
+ std::forward<Params>(params)...);
167
166
// We now have a structured exception ready to use;
168
167
// in future this is the place to put a 'throw'.
169
168
report_exception_to_stderr (to_throw);
@@ -177,20 +176,20 @@ invariant_violated_structured(
177
176
// / \param function : C string giving the name of the function.
178
177
// / \param line : The line number of the invariant
179
178
// / \param reason : brief description of the invariant violation.
179
+ // / \param condition : the condition this invariant is checking.
180
180
#ifdef __GNUC__
181
181
__attribute__ ((noreturn))
182
182
#endif
183
- inline void invariant_violated_string (
183
+ inline void
184
+ invariant_violated_string (
184
185
const std::string &file,
185
186
const std::string &function,
186
187
const int line,
187
- const std::string &reason)
188
+ const std::string &reason,
189
+ const std::string &condition)
188
190
{
189
191
invariant_violated_structured<invariant_failedt>(
190
- file,
191
- function,
192
- line,
193
- reason);
192
+ file, function, line, condition, reason);
194
193
}
195
194
196
195
// These require a trailing semicolon by the user, such that INVARIANT
@@ -207,15 +206,23 @@ inline void invariant_violated_string(
207
206
{ \
208
207
if (!(CONDITION)) \
209
208
invariant_violated_string ( \
210
- __FILE__, __this_function__, __LINE__, (REASON)); /* NOLINT */ \
209
+ __FILE__, \
210
+ __this_function__, \
211
+ __LINE__, \
212
+ (REASON), \
213
+ #CONDITION); /* NOLINT */ \
211
214
} while (false )
212
215
213
216
#define INVARIANT_STRUCTURED (CONDITION, TYPENAME, ...) \
214
217
do /* NOLINT */ \
215
218
{ \
216
219
if (!(CONDITION)) \
217
220
invariant_violated_structured<TYPENAME>( \
218
- __FILE__, __this_function__, __LINE__, __VA_ARGS__); /* NOLINT */ \
221
+ __FILE__, \
222
+ __this_function__, \
223
+ __LINE__, \
224
+ #CONDITION, \
225
+ __VA_ARGS__); /* NOLINT */ \
219
226
} while (false )
220
227
221
228
#endif // End CPROVER_DO_NOT_CHECK / CPROVER_ASSERT / ... if block
@@ -225,15 +232,25 @@ inline void invariant_violated_string(
225
232
// for INVARIANT.
226
233
227
234
// The condition should only contain (unmodified) arguments to the method.
235
+ // Inputs include arguments passed to the function, as well as member
236
+ // variables that the function may read.
228
237
// "The design of the system means that the arguments to this method
229
238
// will always meet this condition".
239
+ //
240
+ // The PRECONDITION documents / checks assumptions about the inputs
241
+ // that is the caller's responsibility to make happen before the call.
230
242
#define PRECONDITION (CONDITION ) INVARIANT(CONDITION, " Precondition" )
231
243
#define PRECONDITION_STRUCTURED (CONDITION, TYPENAME, ...) \
232
244
INVARIANT_STRUCTURED (CONDITION, TYPENAME, __VA_ARGS__)
233
245
234
246
// The condition should only contain variables that will be returned /
235
247
// output without further modification.
236
248
// "The implementation of this method means that the condition will hold".
249
+ //
250
+ // A POSTCONDITION documents what the function can guarantee about its
251
+ // output when it returns, given that it was called with valid inputs.
252
+ // Outputs include the return value of the function, as well as member
253
+ // variables that the function may write.
237
254
#define POSTCONDITION (CONDITION ) INVARIANT(CONDITION, " Postcondition" )
238
255
#define POSTCONDITION_STRUCTURED (CONDITION, TYPENAME, ...) \
239
256
INVARIANT_STRUCTURED (CONDITION, TYPENAME, __VA_ARGS__)
@@ -242,6 +259,10 @@ inline void invariant_violated_string(
242
259
// changed by a previous method call.
243
260
// "The contract of the previous method call means the following
244
261
// condition holds".
262
+ //
263
+ // A difference between CHECK_RETURN and POSTCONDITION is that CHECK_RETURN is
264
+ // a statement about what the caller expects from a function, whereas a
265
+ // POSTCONDITION is a statement about guarantees made by the function itself.
245
266
#define CHECK_RETURN (CONDITION ) INVARIANT(CONDITION, " Check return value" )
246
267
#define CHECK_RETURN_STRUCTURED (CONDITION, TYPENAME, ...) \
247
268
INVARIANT_STRUCTURED (CONDITION, TYPENAME, __VA_ARGS__)
@@ -261,7 +282,7 @@ inline void invariant_violated_string(
261
282
// Legacy annotations
262
283
263
284
// The following should not be used in new code and are only intended
264
- // to migrate documentation and "error handling" in older code
285
+ // to migrate documentation and "error handling" in older code.
265
286
#define TODO INVARIANT (false , " Todo" )
266
287
#define UNIMPLEMENTED INVARIANT (false , " Unimplemented" )
267
288
#define UNHANDLED_CASE INVARIANT (false , " Unhandled case" )
0 commit comments