<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:12.0pt;
        font-family:"Times New Roman",serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
p.msonormal0, li.msonormal0, div.msonormal0
        {mso-style-name:msonormal;
        mso-margin-top-alt:auto;
        margin-right:0cm;
        mso-margin-bottom-alt:auto;
        margin-left:0cm;
        font-size:12.0pt;
        font-family:"Times New Roman",serif;}
span.EmailStyle18
        {mso-style-type:personal-reply;
        font-family:"Calibri",sans-serif;
        color:#1F497D;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri",sans-serif;
        mso-fareast-language:EN-US;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 90.0pt 72.0pt 90.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="FR-CA" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:#1F497D;mso-fareast-language:EN-US">Checking now.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:#1F497D;mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><b><span lang="FR" style="font-size:11.0pt;font-family:"Calibri",sans-serif">De :</span></b><span lang="FR" style="font-size:11.0pt;font-family:"Calibri",sans-serif"> Ilya Biryukov <ibiryukov@google.com>
<br>
<b>Envoyé :</b> 30 août 2018 09:19<br>
<b>À :</b> Alexandre Ganea <alexandre.ganea@ubisoft.com><br>
<b>Cc :</b> llvm-commits <llvm-commits@lists.llvm.org><br>
<b>Objet :</b> Re: [llvm] r341064 - [Error] Add FileError helper; upgrade StringError behavior<o:p></o:p></span></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<p class="MsoNormal">This seems to break the build:<o:p></o:p></p>
<div>
<p class="MsoNormal">../include/llvm/Support/Error.h:1219:11: error: default arguments cannot be added to a function template that has already been declared<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Could you take a look please?<o:p></o:p></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal">On Thu, Aug 30, 2018 at 3:11 PM Alexandre Ganea via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<o:p></o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-right:0cm">
<p class="MsoNormal">Author: aganea<br>
Date: Thu Aug 30 06:10:42 2018<br>
New Revision: 341064<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=341064&view=rev" target="_blank">
http://llvm.org/viewvc/llvm-project?rev=341064&view=rev</a><br>
Log:<br>
[Error] Add FileError helper; upgrade StringError behavior<br>
<br>
FileError is meant to encapsulate both an Error and a file name/path. It should be used in cases where an Error occurs deep down the call chain, and we want to return it to the caller along with the file name.<br>
<br>
StringError was updated to display the error messages in different ways. These can be:<br>
<br>
1. display the error_code message, and convert to the same error_code (ECError behavior)<br>
2. display an arbitrary string, and convert to a provided error_code (current StringError behavior)<br>
3. display both an error_code message and a string, in this order; and convert to the same error_code<br>
<br>
These behaviors can be triggered depending on the constructor. The goal is to use StringError as a base class, when a library needs to provide a explicit Error type.<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D50807" target="_blank">
https://reviews.llvm.org/D50807</a><br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/Support/Error.h<br>
    llvm/trunk/lib/Support/Error.cpp<br>
    llvm/trunk/unittests/Support/ErrorTest.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/Support/Error.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Error.h?rev=341064&r1=341063&r2=341064&view=diff" target="_blank">
http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Error.h?rev=341064&r1=341063&r2=341064&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Support/Error.h (original)<br>
+++ llvm/trunk/include/llvm/Support/Error.h Thu Aug 30 06:10:42 2018<br>
@@ -156,9 +156,10 @@ private:<br>
 /// they're moved-assigned or constructed from Success values that have already<br>
 /// been checked. This enforces checking through all levels of the call stack.<br>
 class LLVM_NODISCARD Error {<br>
-  // ErrorList needs to be able to yank ErrorInfoBase pointers out of this<br>
-  // class to add to the error list.<br>
+  // Both ErrorList and FileError need to be able to yank ErrorInfoBase<br>
+  // pointers out of this class to add to the error list.<br>
   friend class ErrorList;<br>
+  friend class FileError;<br>
<br>
   // handleErrors needs to be able to set the Checked flag.<br>
   template <typename... HandlerTs><br>
@@ -343,6 +344,8 @@ template <typename ErrT, typename... Arg<br>
 template <typename ThisErrT, typename ParentErrT = ErrorInfoBase><br>
 class ErrorInfo : public ParentErrT {<br>
 public:<br>
+  using ParentErrT::ParentErrT; // inherit constructors<br>
+<br>
   static const void *classID() { return &ThisErrT::ID; }<br>
<br>
   const void *dynamicClassID() const override { return &ThisErrT::ID; }<br>
@@ -1110,10 +1113,33 @@ template <typename T> ErrorOr<T> expecte<br>
 /// StringError is useful in cases where the client is not expected to be able<br>
 /// to consume the specific error message programmatically (for example, if the<br>
 /// error message is to be presented to the user).<br>
+///<br>
+/// StringError can also be used when additional information is to be printed<br>
+/// along with a error_code message. Depending on the constructor called, this<br>
+/// class can either display:<br>
+///    1. the error_code message (ECError behavior)<br>
+///    2. a string<br>
+///    3. the error_code message and a string<br>
+///<br>
+/// These behaviors are useful when subtyping is required; for example, when a<br>
+/// specific library needs an explicit error type. In the example below,<br>
+/// PDBError is derived from StringError:<br>
+///<br>
+///   @code{.cpp}<br>
+///   Expected<int> foo() {<br>
+///      return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading,<br>
+///                                        "Additional information");<br>
+///   }<br>
+///   @endcode<br>
+///<br>
 class StringError : public ErrorInfo<StringError> {<br>
 public:<br>
   static char ID;<br>
<br>
+  // Prints EC + S and converts to EC<br>
+  StringError(std::error_code EC, const Twine &S = Twine());<br>
+<br>
+  // Prints S and converts to EC<br>
   StringError(const Twine &S, std::error_code EC);<br>
<br>
   void log(raw_ostream &OS) const override;<br>
@@ -1124,6 +1150,7 @@ public:<br>
 private:<br>
   std::string Msg;<br>
   std::error_code EC;<br>
+  const bool PrintMsgOnly = false;<br>
 };<br>
<br>
 /// Create formatted StringError object.<br>
@@ -1138,6 +1165,61 @@ Error createStringError(std::error_code<br>
<br>
 Error createStringError(std::error_code EC, char const *Msg);<br>
<br>
+/// This class wraps a filename and another Error.<br>
+///<br>
+/// In some cases, an error needs to live along a 'source' name, in order to<br>
+/// show more detailed information to the user.<br>
+class FileError final : public ErrorInfo<FileError> {<br>
+<br>
+  template <class Err><br>
+  friend Error createFileError(<br>
+      std::string, Err,<br>
+      typename std::enable_if<std::is_base_of<Error, Err>::value &&<br>
+                              !std::is_base_of<ErrorSuccess, Err>::value>::type<br>
+          *);<br>
+<br>
+public:<br>
+  void log(raw_ostream &OS) const override {<br>
+    assert(Err && !FileName.empty() && "Trying to log after takeError().");<br>
+    OS << "'" << FileName << "': ";<br>
+    Err->log(OS);<br>
+  }<br>
+<br>
+  Error takeError() { return Error(std::move(Err)); }<br>
+<br>
+  std::error_code convertToErrorCode() const override;<br>
+<br>
+  // Used by ErrorInfo::classID.<br>
+  static char ID;<br>
+<br>
+private:<br>
+  FileError(std::string F, std::unique_ptr<ErrorInfoBase> E) {<br>
+    assert(E && "Cannot create FileError from Error success value.");<br>
+    assert(!F.empty() &&<br>
+           "The file name provided to FileError must not be empty.");<br>
+    FileName = F;<br>
+    Err = std::move(E);<br>
+  }<br>
+<br>
+  static Error build(std::string F, Error E) {<br>
+    return Error(std::unique_ptr<FileError>(new FileError(F, E.takePayload())));<br>
+  }<br>
+<br>
+  std::string FileName;<br>
+  std::unique_ptr<ErrorInfoBase> Err;<br>
+};<br>
+<br>
+/// Concatenate a source file path and/or name with an Error. The resulting<br>
+/// Error is unchecked.<br>
+template <class Err><br>
+inline Error createFileError(<br>
+    std::string F, Err E,<br>
+    typename std::enable_if<std::is_base_of<Error, Err>::value &&<br>
+                            !std::is_base_of<ErrorSuccess, Err>::value>::type<br>
+        * = nullptr) {<br>
+  return FileError::build(F, std::move(E));<br>
+}<br>
+<br>
 /// Helper for check-and-exit error handling.<br>
 ///<br>
 /// For tool use only. NOT FOR USE IN LIBRARY CODE.<br>
<br>
Modified: llvm/trunk/lib/Support/Error.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Error.cpp?rev=341064&r1=341063&r2=341064&view=diff" target="_blank">
http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Error.cpp?rev=341064&r1=341063&r2=341064&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Support/Error.cpp (original)<br>
+++ llvm/trunk/lib/Support/Error.cpp Thu Aug 30 06:10:42 2018<br>
@@ -19,6 +19,7 @@ namespace {<br>
<br>
   enum class ErrorErrorCode : int {<br>
     MultipleErrors = 1,<br>
+    FileError,<br>
     InconvertibleError<br>
   };<br>
<br>
@@ -37,6 +38,8 @@ namespace {<br>
         return "Inconvertible error value. An error has occurred that could "<br>
                "not be converted to a known std::error_code. Please file a "<br>
                "bug.";<br>
+      case ErrorErrorCode::FileError:<br>
+          return "A file error occurred.";<br>
       }<br>
       llvm_unreachable("Unhandled error code");<br>
     }<br>
@@ -53,6 +56,7 @@ char ErrorInfoBase::ID = 0;<br>
 char ErrorList::ID = 0;<br>
 char ECError::ID = 0;<br>
 char StringError::ID = 0;<br>
+char FileError::ID = 0;<br>
<br>
 void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) {<br>
   if (!E)<br>
@@ -75,6 +79,11 @@ std::error_code inconvertibleErrorCode()<br>
                          *ErrorErrorCat);<br>
 }<br>
<br>
+std::error_code FileError::convertToErrorCode() const {<br>
+  return std::error_code(static_cast<int>(ErrorErrorCode::FileError),<br>
+                         *ErrorErrorCat);<br>
+}<br>
+<br>
 Error errorCodeToError(std::error_code EC) {<br>
   if (!EC)<br>
     return Error::success();<br>
@@ -103,10 +112,21 @@ void Error::fatalUncheckedError() const<br>
 }<br>
 #endif<br>
<br>
-StringError::StringError(const Twine &S, std::error_code EC)<br>
+StringError::StringError(std::error_code EC, const Twine &S)<br>
     : Msg(S.str()), EC(EC) {}<br>
<br>
-void StringError::log(raw_ostream &OS) const { OS << Msg; }<br>
+StringError::StringError(const Twine &S, std::error_code EC)<br>
+    : Msg(S.str()), EC(EC), PrintMsgOnly(true) {}<br>
+<br>
+void StringError::log(raw_ostream &OS) const {<br>
+  if (PrintMsgOnly) {<br>
+    OS << Msg;<br>
+  } else {<br>
+    OS << EC.message();<br>
+    if (!Msg.empty())<br>
+      OS << (" " + Msg);<br>
+  }<br>
+}<br>
<br>
 std::error_code StringError::convertToErrorCode() const {<br>
   return EC;<br>
<br>
Modified: llvm/trunk/unittests/Support/ErrorTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ErrorTest.cpp?rev=341064&r1=341063&r2=341064&view=diff" target="_blank">
http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ErrorTest.cpp?rev=341064&r1=341063&r2=341064&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/Support/ErrorTest.cpp (original)<br>
+++ llvm/trunk/unittests/Support/ErrorTest.cpp Thu Aug 30 06:10:42 2018<br>
@@ -13,6 +13,7 @@<br>
 #include "llvm/ADT/Twine.h"<br>
 #include "llvm/Support/Errc.h"<br>
 #include "llvm/Support/ErrorHandling.h"<br>
+#include "llvm/Support/ManagedStatic.h"<br>
 #include "llvm/Testing/Support/Error.h"<br>
 #include "gtest/gtest-spi.h"<br>
 #include "gtest/gtest.h"<br>
@@ -104,7 +105,7 @@ TEST(Error, CheckedSuccess) {<br>
   EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'";<br>
 }<br>
<br>
-// Test that unchecked succes values cause an abort.<br>
+// Test that unchecked success values cause an abort.<br>
 #if LLVM_ENABLE_ABI_BREAKING_CHECKS<br>
 TEST(Error, UncheckedSuccess) {<br>
   EXPECT_DEATH({ Error E = Error::success(); },<br>
@@ -864,4 +865,113 @@ TEST(Error, C_API) {<br>
   EXPECT_TRUE(GotCE) << "Failed to round-trip ErrorList via C API";<br>
 }<br>
<br>
+TEST(Error, FileErrorTest) {<br>
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST<br>
+    EXPECT_DEATH(<br>
+      {<br>
+        Error S = Error::success();<br>
+        createFileError("file.bin", std::move(S));<br>
+      },<br>
+      "");<br>
+#endif<br>
+  Error E1 = make_error<CustomError>(1);<br>
+  Error FE1 = createFileError("file.bin", std::move(E1));<br>
+  EXPECT_EQ(toString(std::move(FE1)).compare("'file.bin': CustomError {1}"), 0);<br>
+<br>
+  Error E2 = make_error<CustomError>(2);<br>
+  Error FE2 = createFileError("file.bin", std::move(E2));<br>
+  handleAllErrors(std::move(FE2), [](const FileError &F) {<br>
+    EXPECT_EQ(F.message().compare("'file.bin': CustomError {2}"), 0);<br>
+  });<br>
+<br>
+  Error E3 = make_error<CustomError>(3);<br>
+  Error FE3 = createFileError("file.bin", std::move(E3));<br>
+  auto E31 = handleErrors(std::move(FE3), [](std::unique_ptr<FileError> F) {<br>
+    return F->takeError();<br>
+  });<br>
+  handleAllErrors(std::move(E31), [](const CustomError &C) {<br>
+    EXPECT_EQ(C.message().compare("CustomError {3}"), 0);<br>
+  });<br>
+<br>
+  Error FE4 =<br>
+      joinErrors(createFileError("file.bin", make_error<CustomError>(41)),<br>
+                 createFileError("file2.bin", make_error<CustomError>(42)));<br>
+  EXPECT_EQ(toString(std::move(FE4))<br>
+                .compare("'file.bin': CustomError {41}\n"<br>
+                         "'file2.bin': CustomError {42}"),<br>
+            0);<br>
+}<br>
+<br>
+enum class test_error_code {<br>
+  unspecified = 1,<br>
+  error_1,<br>
+  error_2,<br>
+};<br>
+<br>
 } // end anon namespace<br>
+<br>
+namespace std {<br>
+    template <><br>
+    struct is_error_code_enum<test_error_code> : std::true_type {};<br>
+} // namespace std<br>
+<br>
+namespace {<br>
+<br>
+const std::error_category &TErrorCategory();<br>
+<br>
+inline std::error_code make_error_code(test_error_code E) {<br>
+    return std::error_code(static_cast<int>(E), TErrorCategory());<br>
+}<br>
+<br>
+class TestDebugError : public ErrorInfo<TestDebugError, StringError> {<br>
+public:<br>
+    using ErrorInfo<TestDebugError, StringError >::ErrorInfo; // inherit constructors<br>
+    TestDebugError(const Twine &S) : ErrorInfo(S, test_error_code::unspecified) {}<br>
+    static char ID;<br>
+};<br>
+<br>
+class TestErrorCategory : public std::error_category {<br>
+public:<br>
+  const char *name() const noexcept override { return "error"; }<br>
+  std::string message(int Condition) const override {<br>
+    switch (static_cast<test_error_code>(Condition)) {<br>
+    case test_error_code::unspecified:<br>
+      return "An unknown error has occurred.";<br>
+    case test_error_code::error_1:<br>
+      return "Error 1.";<br>
+    case test_error_code::error_2:<br>
+      return "Error 2.";<br>
+    }<br>
+    llvm_unreachable("Unrecognized test_error_code");<br>
+  }<br>
+};<br>
+<br>
+static llvm::ManagedStatic<TestErrorCategory> TestErrCategory;<br>
+const std::error_category &TErrorCategory() { return *TestErrCategory; }<br>
+<br>
+char TestDebugError::ID;<br>
+<br>
+TEST(Error, SubtypeStringErrorTest) {<br>
+  auto E1 = make_error<TestDebugError>(test_error_code::error_1);<br>
+  EXPECT_EQ(toString(std::move(E1)).compare("Error 1."), 0);<br>
+<br>
+  auto E2 = make_error<TestDebugError>(test_error_code::error_1,<br>
+                                       "Detailed information");<br>
+  EXPECT_EQ(toString(std::move(E2)).compare("Error 1. Detailed information"),<br>
+            0);<br>
+<br>
+  auto E3 = make_error<TestDebugError>(test_error_code::error_2);<br>
+  handleAllErrors(std::move(E3), [](const TestDebugError &F) {<br>
+    EXPECT_EQ(F.message().compare("Error 2."), 0);<br>
+  });<br>
+<br>
+  auto E4 = joinErrors(make_error<TestDebugError>(test_error_code::error_1,<br>
+                                                  "Detailed information"),<br>
+                       make_error<TestDebugError>(test_error_code::error_2));<br>
+  EXPECT_EQ(toString(std::move(E4))<br>
+                .compare("Error 1. Detailed information\n"<br>
+                         "Error 2."),<br>
+            0);<br>
+}<br>
+<br>
+} // namespace<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><o:p></o:p></p>
</blockquote>
</div>
<p class="MsoNormal"><br clear="all">
<o:p></o:p></p>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<p class="MsoNormal">-- <o:p></o:p></p>
<div>
<div>
<div>
<div>
<div>
<p class="MsoNormal">Regards,<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">Ilya Biryukov<o:p></o:p></p>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>