<div dir="ltr">I think this change broke the docs bot: <div><a href="http://lab.llvm.org:8011/builders/llvm-sphinx-docs/builds/25/steps/docs-llvm-html/logs/stdio">http://lab.llvm.org:8011/builders/llvm-sphinx-docs/builds/25/steps/docs-llvm-html/logs/stdio</a><br></div><div><pre><span class="gmail-stdout"><font color="#000000" face="courier new, courier, monotype, monospace" size="3">Warning, treated as error:
/home/llvmbb/llvm-build-dir/llvm-sphinx-docs/llvm/src/docs/ProgrammersManual.rst:456: WARNING: Could not lex literal_block as "c++". Highlighting skipped.
</font><br></span></pre>I don't understand why and the docs build fine on my machine.</div><div>Probably the bot has outdated sphinx-build or something. </div><div><br></div><div>r285639 is a blind attempt to fix the docs by removing non-ASCII characters. <br><pre style="font-family:"courier new",courier,monotype,monospace;color:rgb(0,0,0);font-size:medium"><span class="gmail-stdout"><br></span></pre><pre style="font-family:"courier new",courier,monotype,monospace;color:rgb(0,0,0);font-size:medium"><span class="gmail-stdout"><br></span></pre></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Oct 25, 2016 at 2:19 PM, Lang Hames via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: lhames<br>
Date: Tue Oct 25 16:19:30 2016<br>
New Revision: 285122<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=285122&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=285122&view=rev</a><br>
Log:<br>
[docs] Add more Error documentation to the Programmer's Manual.<br>
<br>
This patch updates some of the existing Error examples, expands on the<br>
documentation for handleErrors, and includes new sections that cover<br>
a number of helpful utilities and common error usage idioms.<br>
<br>
<br>
Modified:<br>
llvm/trunk/docs/<wbr>ProgrammersManual.rst<br>
<br>
Modified: llvm/trunk/docs/<wbr>ProgrammersManual.rst<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ProgrammersManual.rst?rev=285122&r1=285121&r2=285122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/docs/<wbr>ProgrammersManual.rst?rev=<wbr>285122&r1=285121&r2=285122&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/docs/<wbr>ProgrammersManual.rst (original)<br>
+++ llvm/trunk/docs/<wbr>ProgrammersManual.rst Tue Oct 25 16:19:30 2016<br>
@@ -337,25 +337,28 @@ Failure values are constructed using ``m<br>
that inherits from the ErrorInfo utility, E.g.:<br>
<br>
.. code-block:: c++<br>
-<br>
- class MyError : public ErrorInfo<MyError> {<br>
+ class BadFileFormat : public ErrorInfo<BadFileFormat> {<br>
public:<br>
- MyError(std::string Msg) : Msg(Msg) {}<br>
- void log(OStream &OS) const override { OS << "MyError - " << Msg; }<br>
static char ID;<br>
- private:<br>
- std::string Msg;<br>
- };<br>
+ std::string Path;<br>
<br>
- char MyError::ID = 0; // In MyError.cpp<br>
+ BadFileFormat(StringRef Path) : Path(Path.str()) {}<br>
<br>
- Error bar() {<br>
- if (checkErrorCondition)<br>
- return make_error<MyError>("Error condition detected");<br>
+ void log(raw_ostream &OS) const override {<br>
+ OS << Path << " is malformed";<br>
+ }<br>
+<br>
+ std::error_code convertToErrorCode() const override {<br>
+ return make_error_code(object_error::<wbr>parse_failed);<br>
+ }<br>
+ };<br>
<br>
- // No error - proceed with bar.<br>
+ char FileExists::ID; // This should be declared in the C++ file.<br>
<br>
- // Return success value.<br>
+ Error printFormattedFile(StringRef Path) {<br>
+ if (<check for valid format>)<br>
+ return make_error<InvalidObjectFile>(<wbr>Path);<br>
+ // print file contents.<br>
return Error::success();<br>
}<br>
<br>
@@ -375,34 +378,56 @@ success, enabling the following idiom:<br>
For functions that can fail but need to return a value the ``Expected<T>``<br>
utility can be used. Values of this type can be constructed with either a<br>
``T``, or an ``Error``. Expected<T> values are also implicitly convertible to<br>
-boolean, but with the opposite convention to Error: true for success, false for<br>
-error. If success, the ``T`` value can be accessed via the dereference operator.<br>
-If failure, the ``Error`` value can be extracted using the ``takeError()``<br>
-method. Idiomatic usage looks like:<br>
+boolean, but with the opposite convention to ``Error``: true for success, false<br>
+for error. If success, the ``T`` value can be accessed via the dereference<br>
+operator. If failure, the ``Error`` value can be extracted using the<br>
+``takeError()`` method. Idiomatic usage looks like:<br>
<br>
.. code-block:: c++<br>
<br>
- Expected<float> parseAndSquareRoot(IStream &IS) {<br>
- float f;<br>
- IS >> f;<br>
- if (f < 0)<br>
- return make_error<FloatingPointError><wbr>(...);<br>
- return sqrt(f);<br>
+ Expected<FormattedFile> openFormattedFile(StringRef Path) {<br>
+ // If badly formatted, return an error.<br>
+ if (auto Err = checkFormat(Path))<br>
+ return std::move(Err);<br>
+ // Otherwise return a FormattedFile instance.<br>
+ return FormattedFile(Path);<br>
}<br>
<br>
- Error foo(IStream &IS) {<br>
- if (auto SqrtOrErr = parseAndSquartRoot(IS)) {<br>
- float Sqrt = *SqrtOrErr;<br>
+ Error processFormattedFile(StringRef Path) {<br>
+ // Try to open a formatted file<br>
+ if (auto FileOrErr = openFormattedFile(Path)) {<br>
+ // On success, grab a reference to the file and continue.<br>
+ auto &File = *FileOrErr;<br>
// ...<br>
- } else<br>
- return SqrtOrErr.takeError();<br>
+ } else
 // On error, extract the Error value and return it.<br>
+ return FileOrErr.takeError();<br>
}<br>
<br>
-All Error instances, whether success or failure, must be either checked or<br>
-moved from (via std::move or a return) before they are destructed. Accidentally<br>
-discarding an unchecked error will cause a program abort at the point where the<br>
-unchecked value's destructor is run, making it easy to identify and fix<br>
-violations of this rule.<br>
+If an ``Expected<T>`` value is in success mode then the ``takeError()`` method<br>
+will return a success value. Using this fact, the above function can be<br>
+rewritten as:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ Error processFormattedFile(StringRef Path) {<br>
+ // Try to open a formatted file<br>
+ auto FileOrErr = openFormattedFile(Path);<br>
+ if (auto Err = FileOrErr.takeError())<br>
+ // On error, extract the Error value and return it.<br>
+ return Err;<br>
+ // On success, grab a reference to the file and continue.<br>
+ auto &File = *FileOrErr;<br>
+ // ...<br>
+ }<br>
+<br>
+This second form is often more readable for functions that involve multiple<br>
+``Expected<T>`` values as it limits the indentation required.<br>
+<br>
+All ``Error`` instances, whether success or failure, must be either checked or<br>
+moved from (via ``std::move`` or a return) before they are destructed.<br>
+Accidentally discarding an unchecked error will cause a program abort at the<br>
+point where the unchecked value's destructor is run, making it easy to identify<br>
+and fix violations of this rule.<br>
<br>
Success values are considered checked once they have been tested (by invoking<br>
the boolean conversion operator):<br>
@@ -428,22 +453,305 @@ been activated:<br>
<br>
.. code-block:: c++<br>
<br>
- auto Err = canFail(...);<br>
- if (auto Err2 =<br>
- handleErrors(std::move(Err),<br>
- [](std::unique_ptr<MyError> M) {<br>
- // Try to handle 'M'. If successful, return a success value from<br>
- // the handler.<br>
- if (tryToHandle(M))<br>
- return Error::success();<br>
-<br>
- // We failed to handle 'M' - return it from the handler.<br>
- // This value will be passed back from catchErrors and<br>
- // wind up in Err2, where it will be returned from this function.<br>
- return Error(std::move(M));<br>
- })))<br>
- return Err2;<br>
+ handleErrors(<br>
+ processFormattedFile(…),<br>
+ [](const BadFileFormat &BFF) {<br>
+ report(“Unable to process “ + BFF.Path + “: bad format†);<br>
+ },<br>
+ [](const FileNotFound &FNF) {<br>
+ report("File not found " + FNF.Path);<br>
+ });<br>
+<br>
+The ``handleErrors`` function takes an error as its first argument, followed by<br>
+a variadic list of "handlers", each of which must be a callable type (a<br>
+function, lambda, or class with a call operator) with one argument. The<br>
+``handleErrors`` function will visit each handler in the sequence and check its<br>
+argument type against the dynamic type of the error, running the first handler<br>
+that matches. This is the same process that is used for catch clauses in C++<br>
+exceptions.<br>
+<br>
+Since the list of handlers passed to ``handleErrors`` may not cover every error<br>
+type that can occur, the ``handleErrors`` function also returns an Error value<br>
+that must be checked or propagated. If the error value that is passed to<br>
+``handleErrors`` does not match any of the handlers it will be returned from<br>
+handleErrors. Idiomatic use of ``handleErrors`` thus looks like:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ if (auto Err =<br>
+ handleErrors(<br>
+ processFormattedFile(...),<br>
+ [](const BadFileFormat &BFF) {<br>
+ report(“Unable to process “ + BFF.Path + “: bad format†);<br>
+ },<br>
+ [](const FileNotFound &FNF) {<br>
+ report("File not found " + FNF.Path);<br>
+ }))<br>
+ return Err;<br>
+<br>
+In cases where you truly know that the handler list is exhaustive the<br>
+``handleAllErrors`` function can be used instead. This is identical to<br>
+``handleErrors`` except that it will terminate the program if an unhandled<br>
+error is passed in, and can therefore return void. The ``handleAllErrors``<br>
+function should generally be avoided: the introduction of a new error type<br>
+elsewhere in the program can easily turn a formerly exhaustive list of errors<br>
+into a non-exhaustive list, risking unexpected program termination. Where<br>
+possible, use handleErrors and propagate unknown errors up the stack instead.<br>
+<br>
+StringError<br>
+"""""""""""<br>
+<br>
+Many kinds of errors have no recovery strategy, the only action that can be<br>
+taken is to report them to the user so that the user can attempt to fix the<br>
+environment. In this case representing the error as a string makes perfect<br>
+sense. LLVM provides the ``StringError class for this purpose. It takes two<br>
+arguments: A string error message, and an equivalent ``std::error_code`` for<br>
+interoperability:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ make_error<StringError>("Bad executable",<br>
+ make_error_code(errc::<wbr>executable_format_error"));<br>
+<br>
+If you're certain that the error you're building will never need to be converted<br>
+to a ``std::error_code`` you can use the ``inconvertibleErrorCode()`` function:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ make_error<StringError>("Bad executable", inconvertibleErrorCode());<br>
+<br>
+This should be done only after careful consideration. If any attempt is made to<br>
+convert this error to a ``std::error_code`` it will trigger immediate program<br>
+termination. Unless you are certain that your errors will not need<br>
+interoperability you should look for an existing ``std::error_code`` that you<br>
+can convert to, and even (as painful as it is) consider introducing a new one as<br>
+a stopgap measure.<br>
+<br>
+Interoperability with std::error_code and ErrorOr<br>
+"""""""""""""""""""""""""""""<wbr>""""""""""""""""""""<br>
+<br>
+Many existing LLVM APIs use ``std::error_code`` and its partner ``ErrorOr<T>``<br>
+(which plays the same role as ``Expected<T>``, but wraps a ``std::error_code``<br>
+rather than an ``Error``). The infectious nature of error types means that an<br>
+attempt to change one of these functions to return ``Error`` or ``Expected<T>``<br>
+instead often results in an avalanche of changes to callers, callers of callers,<br>
+and so on. (The first such attempt, returning an ``Error`` from<br>
+MachOObjectFile’s constructor, was abandoned after the diff reached 3000 lines,<br>
+impacted half a dozen libraries, and was still growing).<br>
+<br>
+To solve this problem, the ``Error``/``std::error_code`` interoperability requirement was<br>
+introduced. Two pairs of functions allow any ``Error`` value to be converted to a<br>
+``std::error_code``, any ``Expected<T>`` to be converted to an ``ErrorOr<T>``, and vice<br>
+versa:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ std::error_code errorToErrorCode(Error Err);<br>
+ Error errorCodeToError(std::error_<wbr>code EC);<br>
+<br>
+ template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> TOrErr);<br>
+ template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> TOrEC);<br>
+<br>
+<br>
+Using these APIs it is easy to make surgical patches that update individual<br>
+functions from ``std::error_code`` to ``Error``, and from ``ErrorOr<T>`` to<br>
+``Expected<T>``.<br>
+<br>
+Returning Errors from error handlers<br>
+"""""""""""""""""""""""""""""<wbr>"""""""<br>
+<br>
+Error recovery attempts may themselves fail. For that reason, ``handleErrors``<br>
+actually recognises three different forms of handler signature:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ // Error must be handled, no new errors produced:<br>
+ void(UserDefinedError &E);<br>
+<br>
+ // Error must be handled, new errors can be produced:<br>
+ Error(UserDefinedError &E);<br>
+<br>
+ // Original error can be inspected, then re-wrapped and returned (or a new<br>
+ // error can be produced):<br>
+ Error(std::unique_ptr<<wbr>UserDefinedError> E);<br>
+<br>
+Any error returned from a handler will be returned from the ``handleErrors``<br>
+function so that it can be handled itself, or propagated up the stack.<br>
+<br>
+Using ExitOnError to simplify tool code<br>
+"""""""""""""""""""""""""""""<wbr>""""""""""<br>
+<br>
+Library code should never call ``exit`` for a recoverable error, however in tool<br>
+code (especially comamnd line tools) this can be a reasonable approach. Calling<br>
+``exit`` upon encountering an error dramatically simplifies control flow as the<br>
+error no longer needs to be propagated up the stack. This allows code to be<br>
+written in straight-line style, as long as each fallible call is wrapped in a<br>
+check and call to exit. The ``ExitOnError``` class supports this pattern by<br>
+providing call operators that inspect ``Error`` values, stripping the error away<br>
+in the success case and logging to ``stderr`` then exiting in the failure case.<br>
+<br>
+To use this class, declare a global ``ExitOnError`` variable in your program:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ ExitOnError ExitOnErr;<br>
+<br>
+Calls to fallible functions can then be wrapped with a call to ``ExitOnErr``,<br>
+turning them into non-failing calls:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ Error mayFail();<br>
+ Expected<int> mayFail2();<br>
+<br>
+ void foo() {<br>
+ ExitOnErr(mayFail());<br>
+ int X = ExitOnErr(mayFail2());<br>
+ }<br>
<br>
+On failure, the error’s log message will be written to ``stderr``, optionally<br>
+preceded by a string “banner†that can be set by calling the setBanner method. A<br>
+mapping can also be supplied from ``Error`` values to exit codes using the<br>
+``setExitCodeMapper`` method:<br>
+<br>
+int main(int argc, char *argv[]) {<br>
+ ExitOnErr.setBanner(std::<wbr>string(argv[0]) + “ error:†);<br>
+ ExitOnErr.setExitCodeMapper(<br>
+ [](const Error &Err) {<br>
+ if (Err.isA<BadFileFormat>())<br>
+ return 2;<br>
+ return 1;<br>
+ });<br>
+<br>
+Use ``ExitOnError`` in your tool code where possible as it can greatly improve<br>
+readability.<br>
+<br>
+Fallible constructors<br>
+"""""""""""""""""""""<br>
+<br>
+Some classes require resource acquisition or other complex initialization that<br>
+can fail during construction. Unfortunately constructors can’t return errors,<br>
+and having clients test objects after they’re constructed to ensure that they’re<br>
+valid is error prone as it’s all too easy to forget the test. To work around<br>
+this, use the named constructor idiom and return an ``Expected<T>``:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ class Foo {<br>
+ public:<br>
+<br>
+
 static Expected<Foo> Create(Resource R1, Resource R2) {<br>
+ Error Err;<br>
+ Foo F(R1, R2, Err);<br>
+ if (Err)<br>
+ return std::move(Err);<br>
+ return std::move(F);<br>
+ }<br>
+<br>
+ private:<br>
+<br>
+ Foo(Resource R1, Resource R2, Error &Err) {<br>
+ ErrorAsOutParameter EAO(&Err);<br>
+ if (auto Err2 = R1.acquire()) {<br>
+ Err = std::move(Err2);<br>
+ return;<br>
+ }<br>
+ Err = R2.acquire();<br>
+ }<br>
+ };<br>
+<br>
+<br>
+Here, the named constructor passes an ``Error`` by reference into the actual<br>
+constructor, which the constructor can then use to return errors. The<br>
+``ErrorAsOutParameter`` utility sets the ``Error`` value's checked flag on entry<br>
+to the constructor so that the error can be assigned to, then resets it on exit<br>
+to force the client (the named constructor) to check the error.<br>
+<br>
+By using this idiom, clients attempting to construct a Foo receive either a<br>
+well-formed Foo or an Error, never an object in an invalid state.<br>
+<br>
+Propagating and consuming errors based on types<br>
+"""""""""""""""""""""""""""""<wbr>""""""""""""""""""<br>
+<br>
+In some contexts, certain types of error are known to be benign. For example,<br>
+when walking an archive, some clients may be happy to skip over badly formatted<br>
+object files rather than terminating the walk immediately. Skipping badly<br>
+formatted objects could be achieved using an elaborate handler method, But the<br>
+Error.h header provides two utilities that make this idiom much cleaner: the<br>
+type inspection method, ``isA``, and the ``consumeError`` function:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ Error walkArchive(Archive A) {<br>
+ for (unsigned I = 0; I != A.numMembers(); ++I) {<br>
+ auto ChildOrErr = A.getMember(I);<br>
+ if (auto Err = ChildOrErr.takeError())<br>
+ if (Err.isA<BadFileFormat>())<br>
+ consumeError(std::move(Err))<br>
+ else<br>
+ return Err;<br>
+ auto &Child = *ChildOrErr;<br>
+ // do work<br>
+ }<br>
+ return Error::success();<br>
+ }<br>
+<br>
+Concatenating Errors with joinErrors<br>
+"""""""""""""""""""""""""""""<wbr>"""""""<br>
+<br>
+In the archive walking example above ``BadFileFormat`` errors are simply<br>
+consumed and ignored. If the client had wanted report these errors after<br>
+completing the walk over the archive they could use the ``joinErrors`` utility:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ Error walkArchive(Archive A) {<br>
+ Error DeferredErrs = Error::success();<br>
+ for (unsigned I = 0; I != A.numMembers(); ++I) {<br>
+ auto ChildOrErr = A.getMember(I);<br>
+ if (auto Err = ChildOrErr.takeError())<br>
+ if (Err.isA<BadFileFormat>())<br>
+ DeferredErrs = joinErrors(std::move(<wbr>DeferredErrs), std::move(Err));<br>
+ else<br>
+ return Err;<br>
+ auto &Child = *ChildOrErr;<br>
+ // do work<br>
+ }<br>
+ return DeferredErrs;<br>
+ }<br>
+<br>
+The ``joinErrors`` routine builds a special error type called ``ErrorList``,<br>
+which holds a list of user defined errors. The ``handleErrors`` routine<br>
+recognizes this type and will attempt to handle each of the contained erorrs in<br>
+order. If all contained errors can be handled, ``handleErrors`` will return<br>
+``Error::success()``, otherwise ``handleErrors`` will concatenate the remaining<br>
+errors and return the resulting ``ErrorList``.<br>
+<br>
+Building fallible iterators and iterator ranges<br>
+"""""""""""""""""""""""""""""<wbr>""""""""""""""""""<br>
+<br>
+The archive walking examples above retrieve archive members by index, however<br>
+this requires considerable boiler-plate for iteration and error checking. We can<br>
+clean this up considerably by using ``Error`` with the "fallible iterator"<br>
+pattern. The usual C++ iterator patterns do not allow for failure on increment,<br>
+but we can incorporate support for it by having iterators hold an Error<br>
+reference through which they can report failure. In this pattern, if an<br>
+increment operation fails the failure is recorded via the Error reference and<br>
+the iterator value is set to the end of the range in order to terminate the<br>
+loop. This ensures that the dereference operation is safe anywhere that an<br>
+ordinary iterator dereference would be safe (i.e. when the iterator is not equal<br>
+to end). Where this pattern is followed (as in the ``llvm::object::Archive``<br>
+class) the result is much cleaner iteration idiom:<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ Error Err;<br>
+ for (auto &Child : Ar->children(Err)) {<br>
+ // Use Child - we only enter the loop when it’s valid.<br>
+ }<br>
+ // Check Err after the loop to ensure it didn’t break due to an error.<br>
+ if (Err)<br>
+ return Err;<br>
<br>
.. _function_apis:<br>
<br>
<br>
<br>
______________________________<wbr>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>