7272// / family of macros, allowing constructs like
7373// / `INVARIANT(x==y, my_invariantt, (T1)actual1, (T2)actual2, ...)`
7474// /
75- class invariant_failedt : public std ::logic_error
75+ class invariant_failedt
7676{
7777 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:
8678 const std::string file;
8779 const std::string function;
8880 const int line;
8981 const std::string backtrace;
82+ const std::string condition;
9083 const std::string reason;
9184
85+ public:
86+ std::string what () const noexcept ;
87+
9288 invariant_failedt (
9389 const std::string &_file,
9490 const std::string &_function,
9591 int _line,
9692 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)
110101 {
111102 }
112103};
@@ -149,9 +140,10 @@ void report_exception_to_stderr(const invariant_failedt &);
149140// / \param file : C string giving the name of the file.
150141// / \param function : C string giving the name of the function.
151142// / \param line : The line number of the invariant
143+ // / \param condition : the condition this invariant is checking.
152144// / \param params : (variadic) parameters to forward to ET's constructor
153145// / its backtrace member will be set before it is used.
154- template <class ET , typename ...Params>
146+ template <class ET , typename ... Params>
155147#ifdef __GNUC__
156148__attribute__ ((noreturn))
157149#endif
@@ -160,10 +152,17 @@ invariant_violated_structured(
160152 const std::string &file,
161153 const std::string &function,
162154 const int line,
155+ const std::string &condition,
163156 Params &&... params)
164157{
165158 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)...);
167166 // We now have a structured exception ready to use;
168167 // in future this is the place to put a 'throw'.
169168 report_exception_to_stderr (to_throw);
@@ -177,20 +176,20 @@ invariant_violated_structured(
177176// / \param function : C string giving the name of the function.
178177// / \param line : The line number of the invariant
179178// / \param reason : brief description of the invariant violation.
179+ // / \param condition : the condition this invariant is checking.
180180#ifdef __GNUC__
181181__attribute__ ((noreturn))
182182#endif
183- inline void invariant_violated_string (
183+ inline void
184+ invariant_violated_string (
184185 const std::string &file,
185186 const std::string &function,
186187 const int line,
187- const std::string &reason)
188+ const std::string &reason,
189+ const std::string &condition)
188190{
189191 invariant_violated_structured<invariant_failedt>(
190- file,
191- function,
192- line,
193- reason);
192+ file, function, line, condition, reason);
194193}
195194
196195// These require a trailing semicolon by the user, such that INVARIANT
@@ -207,15 +206,23 @@ inline void invariant_violated_string(
207206 { \
208207 if (!(CONDITION)) \
209208 invariant_violated_string ( \
210- __FILE__, __this_function__, __LINE__, (REASON)); /* NOLINT */ \
209+ __FILE__, \
210+ __this_function__, \
211+ __LINE__, \
212+ (REASON), \
213+ #CONDITION); /* NOLINT */ \
211214 } while (false )
212215
213216#define INVARIANT_STRUCTURED (CONDITION, TYPENAME, ...) \
214217 do /* NOLINT */ \
215218 { \
216219 if (!(CONDITION)) \
217220 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 */ \
219226 } while (false )
220227
221228#endif // End CPROVER_DO_NOT_CHECK / CPROVER_ASSERT / ... if block
@@ -225,15 +232,25 @@ inline void invariant_violated_string(
225232// for INVARIANT.
226233
227234// 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.
228237// "The design of the system means that the arguments to this method
229238// 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.
230242#define PRECONDITION (CONDITION ) INVARIANT(CONDITION, " Precondition" )
231243#define PRECONDITION_STRUCTURED (CONDITION, TYPENAME, ...) \
232244 INVARIANT_STRUCTURED (CONDITION, TYPENAME, __VA_ARGS__)
233245
234246// The condition should only contain variables that will be returned /
235247// output without further modification.
236248// "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.
237254#define POSTCONDITION (CONDITION ) INVARIANT(CONDITION, " Postcondition" )
238255#define POSTCONDITION_STRUCTURED (CONDITION, TYPENAME, ...) \
239256 INVARIANT_STRUCTURED (CONDITION, TYPENAME, __VA_ARGS__)
@@ -242,6 +259,10 @@ inline void invariant_violated_string(
242259// changed by a previous method call.
243260// "The contract of the previous method call means the following
244261// 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.
245266#define CHECK_RETURN (CONDITION ) INVARIANT(CONDITION, " Check return value" )
246267#define CHECK_RETURN_STRUCTURED (CONDITION, TYPENAME, ...) \
247268 INVARIANT_STRUCTURED (CONDITION, TYPENAME, __VA_ARGS__)
@@ -261,7 +282,7 @@ inline void invariant_violated_string(
261282// Legacy annotations
262283
263284// 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.
265286#define TODO INVARIANT (false , " Todo" )
266287#define UNIMPLEMENTED INVARIANT (false , " Unimplemented" )
267288#define UNHANDLED_CASE INVARIANT (false , " Unhandled case" )
0 commit comments