Skip to content

Commit f7f6d3e

Browse files
committedMar 16, 2016
[Support] Add the 'Error' class for structured error handling.
This patch introduces the Error classs for lightweight, structured, recoverable error handling. It includes utilities for creating, manipulating and handling errors. The scheme is similar to exceptions, in that errors are described with user-defined types. Unlike exceptions however, errors are represented as ordinary return types in the API (similar to the way std::error_code is used). For usage notes see the LLVM programmer's manual, and the Error.h header. Usage examples can be found in unittests/Support/ErrorTest.cpp. Many thanks to David Blaikie, Mehdi Amini, Kevin Enderby and others on the llvm-dev and llvm-commits lists for lots of discussion and review. llvm-svn: 263609
1 parent 39d2411 commit f7f6d3e

File tree

5 files changed

+1378
-0
lines changed

5 files changed

+1378
-0
lines changed
 

‎llvm/docs/ProgrammersManual.rst

+168
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,176 @@ almost never be stored or mentioned directly. They are intended solely for use
263263
when defining a function which should be able to efficiently accept concatenated
264264
strings.
265265

266+
.. _error_apis:
267+
268+
Error handling
269+
--------------
270+
271+
Proper error handling helps us identify bugs in our code, and helps end-users
272+
understand errors in their tool usage. Errors fall into two broad categories:
273+
*programmatic* and *recoverable*, with different strategies for handling and
274+
reporting.
275+
276+
Programmatic Errors
277+
^^^^^^^^^^^^^^^^^^^
278+
279+
Programmatic errors are violations of program invariants or API contracts, and
280+
represent bugs within the program itself. Our aim is to document invariants, and
281+
to abort quickly at the point of failure (providing some basic diagnostic) when
282+
invariants are broken at runtime.
283+
284+
The fundamental tools for handling programmatic errors are assertions and the
285+
llvm_unreachable function. Assertions are used to express invariant conditions,
286+
and should include a message describing the invariant:
287+
288+
.. code-block:: c++
289+
290+
assert(isPhysReg(R) && "All virt regs should have been allocated already.");
291+
292+
The llvm_unreachable function can be used to document areas of control flow
293+
that should never be entered if the program invariants hold:
294+
295+
.. code-block:: c++
296+
297+
enum { Foo, Bar, Baz } X = foo();
298+
299+
switch (X) {
300+
case Foo: /* Handle Foo */; break;
301+
case Bar: /* Handle Bar */; break;
302+
default:
303+
llvm_unreachable("X should be Foo or Bar here");
304+
}
305+
306+
Recoverable Errors
307+
^^^^^^^^^^^^^^^^^^
308+
309+
Recoverable errors represent an error in the program's environment, for example
310+
a resource failure (a missing file, a dropped network connection, etc.), or
311+
malformed input. These errors should be detected and communicated to a level of
312+
the program where they can be handled appropriately. Handling the error may be
313+
as simple as reporting the issue to the user, or it may involve attempts at
314+
recovery.
315+
316+
Recoverable errors are modeled using LLVM's ``Error`` scheme. This scheme
317+
represents errors using function return values, similar to classic C integer
318+
error codes, or C++'s ``std::error_code``. However, the ``Error`` class is
319+
actually a lightweight wrapper for user-defined error types, allowing arbitrary
320+
information to be attached to describe the error. This is similar to the way C++
321+
exceptions allow throwing of user-defined types.
322+
323+
Success values are created by calling ``Error::success()``:
324+
325+
.. code-block:: c++
326+
327+
Error foo() {
328+
// Do something.
329+
// Return success.
330+
return Error::success();
331+
}
332+
333+
Success values are very cheap to construct and return - they have minimal
334+
impact on program performance.
335+
336+
Failure values are constructed using ``make_error<T>``, where ``T`` is any class
337+
that inherits from the ErrorInfo utility:
338+
339+
.. code-block:: c++
340+
341+
class MyError : public ErrorInfo<MyError> {
342+
public:
343+
MyError(std::string Msg) : Msg(Msg) {}
344+
void log(OStream &OS) const override { OS << "MyError - " << Msg; }
345+
private:
346+
std::string Msg;
347+
};
348+
349+
Error bar() {
350+
if (checkErrorCondition)
351+
return make_error<MyError>("Error condition detected");
352+
353+
// No error - proceed with bar.
354+
355+
// Return success value.
356+
return Error::success();
357+
}
358+
359+
For functions that can fail but need to return a value the ``Expected<T>``
360+
utility can be used. Values of this type can be constructed with either a
361+
``T``, or a ``Error``. Values are implicitly convertible to boolean: true
362+
for success, false for error. If success, the ``T`` value can be accessed via
363+
the dereference operator. If failure, the ``Error`` value can be extracted
364+
using the ``takeError()`` method:
365+
366+
.. code-block:: c++
367+
368+
Expected<float> parseAndSquareRoot(IStream &IS) {
369+
float f;
370+
OS >> f;
371+
if (f < 0)
372+
return make_error<FloatingPointError>(...);
373+
return sqrt(f);
374+
}
375+
376+
Error foo(IStream &IS) {
377+
if (auto SqrtOrErr = parseAndSquartRoot(IS)) {
378+
float Sqrt = *SqrtOrErr;
379+
// ...
380+
} else
381+
return SqrtOrErr.takeError();
382+
}
383+
384+
All Error instances, whether success or failure, must be either checked or
385+
moved from (via std::move or a return) before they are destructed. Accidentally
386+
discarding an unchecked error will cause a program abort at the point where the
387+
unchecked value's destructor is run, making it easy to identify and fix
388+
violations of this rule.
389+
390+
Success values are considered checked once they have been tested (by invoking
391+
the boolean conversion operator):
392+
393+
.. code-block:: c++
394+
395+
if (auto Err = canFail(...))
396+
return Err; // Failure value - move error to caller.
397+
398+
// Safe to continue: Err was checked.
399+
400+
In contrast, the following code will always cause an abort, regardless of the
401+
return value of ``foo``:
402+
403+
.. code-block:: c++
404+
405+
canFail();
406+
// Program will always abort here, even if canFail() returns Success, since
407+
// the value is not checked.
408+
409+
Failure values are considered checked once a handler for the error type has
410+
been activated:
411+
412+
.. code-block:: c++
413+
414+
auto Err = canFail(...);
415+
if (auto Err2 =
416+
handleErrors(std::move(Err),
417+
[](std::unique_ptr<MyError> M) {
418+
// Try to handle 'M'. If successful, return a success value from
419+
// the handler.
420+
if (tryToHandle(M))
421+
return Error::success();
422+
423+
// We failed to handle 'M' - return it from the handler.
424+
// This value will be passed back from catchErrors and
425+
// wind up in Err2, where it will be returned from this function.
426+
return Error(std::move(M));
427+
})))
428+
return Err2;
429+
430+
266431
.. _function_apis:
267432

433+
More information on Error and its related utilities can be found in the
434+
Error.h header file.
435+
268436
Passing functions and other callable objects
269437
--------------------------------------------
270438

0 commit comments

Comments
 (0)
Please sign in to comment.