[clang] edb1a1d - Reland "[Clang][Bundler] Error reporting improvements"

Sergey Dmitriev via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 25 19:32:50 PDT 2019


Author: Sergey Dmitriev
Date: 2019-10-25T19:00:06-07:00
New Revision: edb1a1de1b79c190ed7b76cf889a295c72e73729

URL: https://github.com/llvm/llvm-project/commit/edb1a1de1b79c190ed7b76cf889a295c72e73729
DIFF: https://github.com/llvm/llvm-project/commit/edb1a1de1b79c190ed7b76cf889a295c72e73729.diff

LOG: Reland "[Clang][Bundler] Error reporting improvements"

- Changed FileHandler read/write methods to return llvm::Error
- Using unified way of reporting errors
- Removed trailing '.' from the error messages

Differential Revision: https://reviews.llvm.org/D67031

Added: 
    

Modified: 
    clang/test/Driver/clang-offload-bundler.c
    clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp

Removed: 
    


################################################################################
diff  --git a/clang/test/Driver/clang-offload-bundler.c b/clang/test/Driver/clang-offload-bundler.c
index be17b092ef34..35c327c56b3b 100644
--- a/clang/test/Driver/clang-offload-bundler.c
+++ b/clang/test/Driver/clang-offload-bundler.c
@@ -52,27 +52,27 @@
 // Check errors.
 //
 // RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i -unbundle 2>&1 | FileCheck %s --check-prefix CK-ERR1
-// CK-ERR1: error: only one input file supported in unbundling mode.
-// CK-ERR1: error: number of output files and targets should match in unbundling mode.
+// CK-ERR1: error: only one input file supported in unbundling mode
+// CK-ERR1: error: number of output files and targets should match in unbundling mode
 
 // RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR2
 // RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1 -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR2
-// CK-ERR2: error: number of input files and targets should match in bundling mode.
+// CK-ERR2: error: number of input files and targets should match in bundling mode
 
 // RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.i,%t.tgt1,%t.tgt2 -inputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR3
-// CK-ERR3: error: only one output file supported in bundling mode.
-// CK-ERR3: error: number of input files and targets should match in bundling mode.
+// CK-ERR3: error: only one output file supported in bundling mode
+// CK-ERR3: error: number of input files and targets should match in bundling mode
 
 // RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu -outputs=%t.i,%t.tgt1,%t.tgt2 -inputs=%t.bundle.i -unbundle 2>&1 | FileCheck %s --check-prefix CK-ERR4
 // RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.i,%t.tgt1 -inputs=%t.bundle.i -unbundle 2>&1 | FileCheck %s --check-prefix CK-ERR4
-// CK-ERR4: error: number of output files and targets should match in unbundling mode.
+// CK-ERR4: error: number of output files and targets should match in unbundling mode
 
-// RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2.notexist -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR5
-// RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.i,%t.tgt1,%t.tgt2 -inputs=%t.bundle.i.notexist -unbundle 2>&1 | FileCheck %s --check-prefix CK-ERR5
-// CK-ERR5: error: Can't open file {{.+}}.notexist: {{N|n}}o such file or directory
+// RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2.notexist -outputs=%t.bundle.i 2>&1 | FileCheck %s -DFILE=%t.tgt2.notexist --check-prefix CK-ERR5
+// RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.i,%t.tgt1,%t.tgt2 -inputs=%t.bundle.i.notexist -unbundle 2>&1 | FileCheck %s -DFILE=%t.bundle.i.notexist --check-prefix CK-ERR5
+// CK-ERR5: error: '[[FILE]]': {{N|n}}o such file or directory
 
-// RUN: not clang-offload-bundler -type=invalid -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR6
-// CK-ERR6: error: invalid file type specified.
+// RUN: not clang-offload-bundler -type=invalid -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i 2>&1 | FileCheck %s -DTYPE=invalid --check-prefix CK-ERR6
+// CK-ERR6: error: '[[TYPE]]': invalid file type specified
 
 // RUN: not clang-offload-bundler 2>&1 | FileCheck %s --check-prefix CK-ERR7
 // CK-ERR7-DAG: clang-offload-bundler: for the --type option: must be specified at least once!
@@ -81,14 +81,14 @@
 // CK-ERR7-DAG: clang-offload-bundler: for the --targets option: must be specified at least once!
 
 // RUN: not clang-offload-bundler -type=i -targets=hxst-powerpcxxle-ibm-linux-gnu,openxp-pxxerpc64le-ibm-linux-gnu,xpenmp-x86_xx-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR8
-// CK-ERR8: error: invalid target 'hxst-powerpcxxle-ibm-linux-gnu', unknown offloading kind 'hxst', unknown target triple 'powerpcxxle-ibm-linux-gnu'.
-// CK-ERR8: error: invalid target 'openxp-pxxerpc64le-ibm-linux-gnu', unknown offloading kind 'openxp', unknown target triple 'pxxerpc64le-ibm-linux-gnu'.
-// CK-ERR8: error: invalid target 'xpenmp-x86_xx-pc-linux-gnu', unknown offloading kind 'xpenmp', unknown target triple 'x86_xx-pc-linux-gnu'.
+// CK-ERR8: error: invalid target 'hxst-powerpcxxle-ibm-linux-gnu', unknown offloading kind 'hxst', unknown target triple 'powerpcxxle-ibm-linux-gnu'
+// CK-ERR8: error: invalid target 'openxp-pxxerpc64le-ibm-linux-gnu', unknown offloading kind 'openxp', unknown target triple 'pxxerpc64le-ibm-linux-gnu'
+// CK-ERR8: error: invalid target 'xpenmp-x86_xx-pc-linux-gnu', unknown offloading kind 'xpenmp', unknown target triple 'x86_xx-pc-linux-gnu'
 
 // RUN: not clang-offload-bundler -type=i -targets=openmp-powerpc64le-linux,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR9A
 // RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,host-%itanium_abi_triple,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR9B
-// CK-ERR9A: error: expecting exactly one host target but got 0.
-// CK-ERR9B: error: expecting exactly one host target but got 2.
+// CK-ERR9A: error: expecting exactly one host target but got 0
+// CK-ERR9B: error: expecting exactly one host target but got 2
 
 //
 // Check text bundle. This is a readable format, so we check for the format we expect to find.

diff  --git a/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
index 72def7756dd7..a75d2a630cf4 100644
--- a/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
+++ b/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
@@ -26,15 +26,17 @@
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Program.h"
-#include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/StringSaver.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 #include <cassert>
 #include <cstddef>
@@ -42,6 +44,7 @@
 #include <memory>
 #include <string>
 #include <system_error>
+#include <utility>
 
 using namespace llvm;
 using namespace llvm::object;
@@ -123,36 +126,37 @@ class FileHandler {
   virtual ~FileHandler() {}
 
   /// Update the file handler with information from the header of the bundled
-  /// file
-  virtual void ReadHeader(MemoryBuffer &Input) = 0;
+  /// file.
+  virtual Error ReadHeader(MemoryBuffer &Input) = 0;
 
-  /// Read the marker of the next bundled to be read in the file. The triple of
-  /// the target associated with that bundle is returned. An empty string is
-  /// returned if there are no more bundles to be read.
-  virtual StringRef ReadBundleStart(MemoryBuffer &Input) = 0;
+  /// Read the marker of the next bundled to be read in the file. The bundle
+  /// name is returned if there is one in the file, or `None` if there are no
+  /// more bundles to be read.
+  virtual Expected<Optional<StringRef>>
+  ReadBundleStart(MemoryBuffer &Input) = 0;
 
   /// Read the marker that closes the current bundle.
-  virtual void ReadBundleEnd(MemoryBuffer &Input) = 0;
+  virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
 
   /// Read the current bundle and write the result into the stream \a OS.
-  virtual void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
+  virtual Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
 
   /// Write the header of the bundled file to \a OS based on the information
   /// gathered from \a Inputs.
-  virtual void WriteHeader(raw_fd_ostream &OS,
-                           ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
+  virtual Error WriteHeader(raw_fd_ostream &OS,
+                            ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
 
   /// Write the marker that initiates a bundle for the triple \a TargetTriple to
   /// \a OS.
-  virtual void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
+  virtual Error WriteBundleStart(raw_fd_ostream &OS,
+                                 StringRef TargetTriple) = 0;
 
   /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
-  /// OS. Return true if any error was found.
-
-  virtual bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
+  /// OS.
+  virtual Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
 
   /// Write the bundle from \a Input into \a OS.
-  virtual void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
+  virtual Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
 };
 
 /// Handler for binary files. The bundled file will have the following format
@@ -224,7 +228,7 @@ class BinaryFileHandler final : public FileHandler {
 
   ~BinaryFileHandler() final {}
 
-  void ReadHeader(MemoryBuffer &Input) final {
+  Error ReadHeader(MemoryBuffer &Input) final {
     StringRef FC = Input.getBuffer();
 
     // Initialize the current bundle with the end of the container.
@@ -233,16 +237,16 @@ class BinaryFileHandler final : public FileHandler {
     // Check if buffer is smaller than magic string.
     size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
     if (ReadChars > FC.size())
-      return;
+      return Error::success();
 
     // Check if no magic was found.
     StringRef Magic(FC.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
     if (!Magic.equals(OFFLOAD_BUNDLER_MAGIC_STR))
-      return;
+      return Error::success();
 
     // Read number of bundles.
     if (ReadChars + 8 > FC.size())
-      return;
+      return Error::success();
 
     uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
     ReadChars += 8;
@@ -252,35 +256,35 @@ class BinaryFileHandler final : public FileHandler {
 
       // Read offset.
       if (ReadChars + 8 > FC.size())
-        return;
+        return Error::success();
 
       uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
       ReadChars += 8;
 
       // Read size.
       if (ReadChars + 8 > FC.size())
-        return;
+        return Error::success();
 
       uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
       ReadChars += 8;
 
       // Read triple size.
       if (ReadChars + 8 > FC.size())
-        return;
+        return Error::success();
 
       uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
       ReadChars += 8;
 
       // Read triple.
       if (ReadChars + TripleSize > FC.size())
-        return;
+        return Error::success();
 
       StringRef Triple(&FC.data()[ReadChars], TripleSize);
       ReadChars += TripleSize;
 
       // Check if the offset and size make sense.
       if (!Offset || Offset + Size > FC.size())
-        return;
+        return Error::success();
 
       assert(BundlesInfo.find(Triple) == BundlesInfo.end() &&
              "Triple is duplicated??");
@@ -289,28 +293,31 @@ class BinaryFileHandler final : public FileHandler {
     // Set the iterator to where we will start to read.
     CurBundleInfo = BundlesInfo.end();
     NextBundleInfo = BundlesInfo.begin();
+    return Error::success();
   }
 
-  StringRef ReadBundleStart(MemoryBuffer &Input) final {
+  Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
     if (NextBundleInfo == BundlesInfo.end())
-      return StringRef();
+      return None;
     CurBundleInfo = NextBundleInfo++;
     return CurBundleInfo->first();
   }
 
-  void ReadBundleEnd(MemoryBuffer &Input) final {
+  Error ReadBundleEnd(MemoryBuffer &Input) final {
     assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
+    return Error::success();
   }
 
-  void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+  Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
     assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
     StringRef FC = Input.getBuffer();
     OS.write(FC.data() + CurBundleInfo->second.Offset,
              CurBundleInfo->second.Size);
+    return Error::success();
   }
 
-  void WriteHeader(raw_fd_ostream &OS,
-                   ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+  Error WriteHeader(raw_fd_ostream &OS,
+                    ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
     // Compute size of the header.
     uint64_t HeaderSize = 0;
 
@@ -329,7 +336,7 @@ class BinaryFileHandler final : public FileHandler {
 
     unsigned Idx = 0;
     for (auto &T : TargetNames) {
-      MemoryBuffer &MB = *Inputs[Idx++].get();
+      MemoryBuffer &MB = *Inputs[Idx++];
       // Bundle offset.
       Write8byteIntegerToBuffer(OS, HeaderSize);
       // Size of the bundle (adds to the next bundle's offset)
@@ -340,25 +347,26 @@ class BinaryFileHandler final : public FileHandler {
       // Triple
       OS << T;
     }
+    return Error::success();
   }
 
-  void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {}
+  Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
+    return Error::success();
+  }
 
-  bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
-    return false;
+  Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
+    return Error::success();
   }
 
-  void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+  Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
     OS.write(Input.getBufferStart(), Input.getBufferSize());
+    return Error::success();
   }
 };
 
 /// Handler for object files. The bundles are organized by sections with a
 /// designated name.
 ///
-/// In order to bundle we create an IR file with the content of each section and
-/// use incremental linking to produce the resulting object.
-///
 /// To unbundle, we just copy the contents of the designated section.
 class ObjectFileHandler final : public FileHandler {
 
@@ -368,26 +376,19 @@ class ObjectFileHandler final : public FileHandler {
   /// Return the input file contents.
   StringRef getInputFileContents() const { return Obj->getData(); }
 
-  /// Return true if the provided section is an offload section and return the
-  /// triple by reference.
-  static bool IsOffloadSection(SectionRef CurSection,
-                               StringRef &OffloadTriple) {
-    StringRef SectionName;
-    if (Expected<StringRef> NameOrErr = CurSection.getName())
-      SectionName = *NameOrErr;
-    else
-      consumeError(NameOrErr.takeError());
-
-    if (SectionName.empty())
-      return false;
+  /// Return bundle name (<kind>-<triple>) if the provided section is an offload
+  /// section.
+  static Expected<Optional<StringRef>> IsOffloadSection(SectionRef CurSection) {
+    Expected<StringRef> NameOrErr = CurSection.getName();
+    if (!NameOrErr)
+      return NameOrErr.takeError();
 
     // If it does not start with the reserved suffix, just skip this section.
-    if (!SectionName.startswith(OFFLOAD_BUNDLER_MAGIC_STR))
-      return false;
+    if (!NameOrErr->startswith(OFFLOAD_BUNDLER_MAGIC_STR))
+      return None;
 
     // Return the triple that is right after the reserved prefix.
-    OffloadTriple = SectionName.substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
-    return true;
+    return NameOrErr->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
   }
 
   /// Total number of inputs.
@@ -409,71 +410,67 @@ class ObjectFileHandler final : public FileHandler {
 
   ~ObjectFileHandler() final {}
 
-  void ReadHeader(MemoryBuffer &Input) final {}
+  Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
 
-  StringRef ReadBundleStart(MemoryBuffer &Input) final {
+  Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
     while (NextSection != Obj->section_end()) {
       CurrentSection = NextSection;
       ++NextSection;
 
-      StringRef OffloadTriple;
       // Check if the current section name starts with the reserved prefix. If
       // so, return the triple.
-      if (IsOffloadSection(*CurrentSection, OffloadTriple))
-        return OffloadTriple;
+      Expected<Optional<StringRef>> TripleOrErr =
+          IsOffloadSection(*CurrentSection);
+      if (!TripleOrErr)
+        return TripleOrErr.takeError();
+      if (*TripleOrErr)
+        return **TripleOrErr;
     }
-    return StringRef();
+    return None;
   }
 
-  void ReadBundleEnd(MemoryBuffer &Input) final {}
-
-  void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
-    // If the current section has size one, that means that the content we are
-    // interested in is the file itself. Otherwise it is the content of the
-    // section.
-    //
-    // TODO: Instead of copying the input file as is, deactivate the section
-    // that is no longer needed.
+  Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }
 
+  Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
     Expected<StringRef> Content = CurrentSection->getContents();
-    if (!Content) {
-      consumeError(Content.takeError());
-      return;
-    }
+    if (!Content)
+      return Content.takeError();
 
     OS.write(Content->data(), Content->size());
+    return Error::success();
   }
 
-  void WriteHeader(raw_fd_ostream &OS,
-                   ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+  Error WriteHeader(raw_fd_ostream &OS,
+                    ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
     assert(HostInputIndex != ~0u && "Host input index not defined.");
 
     // Record number of inputs.
     NumberOfInputs = Inputs.size();
+    return Error::success();
   }
 
-  void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
+  Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
     ++NumberOfProcessedInputs;
+    return Error::success();
   }
 
-  bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
+  Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
     assert(NumberOfProcessedInputs <= NumberOfInputs &&
            "Processing more inputs that actually exist!");
     assert(HostInputIndex != ~0u && "Host input index not defined.");
 
     // If this is not the last output, we don't have to do anything.
     if (NumberOfProcessedInputs != NumberOfInputs)
-      return false;
+      return Error::success();
 
     // Find llvm-objcopy in order to create the bundle binary.
     ErrorOr<std::string> Objcopy = sys::findProgramByName(
         "llvm-objcopy", sys::path::parent_path(BundlerExecutable));
     if (!Objcopy)
       Objcopy = sys::findProgramByName("llvm-objcopy");
-    if (!Objcopy) {
-      errs() << "error: unable to find 'llvm-objcopy' in path.\n";
-      return true;
-    }
+    if (!Objcopy)
+      return createStringError(Objcopy.getError(),
+                               "unable to find 'llvm-objcopy' in path");
 
     // We write to the output file directly. So, we close it and use the name
     // to pass down to llvm-objcopy.
@@ -493,21 +490,22 @@ class ObjectFileHandler final : public FileHandler {
     // If the user asked for the commands to be printed out, we do that instead
     // of executing it.
     if (PrintExternalCommands) {
-      errs() << "\"" << Objcopy.get() << "\"";
+      errs() << "\"" << *Objcopy << "\"";
       for (StringRef Arg : drop_begin(ObjcopyArgs, 1))
         errs() << " \"" << Arg << "\"";
       errs() << "\n";
     } else {
-      if (sys::ExecuteAndWait(Objcopy.get(), ObjcopyArgs)) {
-        errs() << "error: llvm-objcopy tool failed.\n";
-        return true;
-      }
+      if (sys::ExecuteAndWait(*Objcopy, ObjcopyArgs))
+        return createStringError(inconvertibleErrorCode(),
+                                 "'llvm-objcopy' tool failed");
     }
 
-    return false;
+    return Error::success();
   }
 
-  void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {}
+  Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+    return Error::success();
+  }
 };
 
 /// Handler for text files. The bundled file will have the following format.
@@ -533,15 +531,15 @@ class TextFileHandler final : public FileHandler {
   size_t ReadChars = 0u;
 
 protected:
-  void ReadHeader(MemoryBuffer &Input) final {}
+  Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
 
-  StringRef ReadBundleStart(MemoryBuffer &Input) final {
+  Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
     StringRef FC = Input.getBuffer();
 
     // Find start of the bundle.
     ReadChars = FC.find(BundleStartString, ReadChars);
     if (ReadChars == FC.npos)
-      return StringRef();
+      return None;
 
     // Get position of the triple.
     size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
@@ -549,7 +547,7 @@ class TextFileHandler final : public FileHandler {
     // Get position that closes the triple.
     size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);
     if (TripleEnd == FC.npos)
-      return StringRef();
+      return None;
 
     // Next time we read after the new line.
     ++ReadChars;
@@ -557,21 +555,21 @@ class TextFileHandler final : public FileHandler {
     return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
   }
 
-  void ReadBundleEnd(MemoryBuffer &Input) final {
+  Error ReadBundleEnd(MemoryBuffer &Input) final {
     StringRef FC = Input.getBuffer();
 
     // Read up to the next new line.
     assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");
 
     size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);
-    if (TripleEnd == FC.npos)
-      return;
+    if (TripleEnd != FC.npos)
+      // Next time we read after the new line.
+      ++ReadChars;
 
-    // Next time we read after the new line.
-    ++ReadChars;
+    return Error::success();
   }
 
-  void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+  Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
     StringRef FC = Input.getBuffer();
     size_t BundleStart = ReadChars;
 
@@ -580,22 +578,28 @@ class TextFileHandler final : public FileHandler {
 
     StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
     OS << Bundle;
+
+    return Error::success();
   }
 
-  void WriteHeader(raw_fd_ostream &OS,
-                   ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {}
+  Error WriteHeader(raw_fd_ostream &OS,
+                    ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+    return Error::success();
+  }
 
-  void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
+  Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
     OS << BundleStartString << TargetTriple << "\n";
+    return Error::success();
   }
 
-  bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
+  Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
     OS << BundleEndString << TargetTriple << "\n";
-    return false;
+    return Error::success();
   }
 
-  void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+  Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
     OS << Input.getBuffer();
+    return Error::success();
   }
 
 public:
@@ -611,61 +615,60 @@ class TextFileHandler final : public FileHandler {
 /// Return an appropriate object file handler. We use the specific object
 /// handler if we know how to deal with that format, otherwise we use a default
 /// binary file handler.
-static FileHandler *CreateObjectFileHandler(MemoryBuffer &FirstInput) {
+static std::unique_ptr<FileHandler>
+CreateObjectFileHandler(MemoryBuffer &FirstInput) {
   // Check if the input file format is one that we know how to deal with.
   Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput);
 
   // We only support regular object files. If failed to open the input as a
   // known binary or this is not an object file use the default binary handler.
   if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
-    return new BinaryFileHandler();
+    return std::make_unique<BinaryFileHandler>();
 
   // Otherwise create an object file handler. The handler will be owned by the
   // client of this function.
-  return new ObjectFileHandler(
+  return std::make_unique<ObjectFileHandler>(
       std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())));
 }
 
 /// Return an appropriate handler given the input files and options.
-static FileHandler *CreateFileHandler(MemoryBuffer &FirstInput) {
+static Expected<std::unique_ptr<FileHandler>>
+CreateFileHandler(MemoryBuffer &FirstInput) {
   if (FilesType == "i")
-    return new TextFileHandler(/*Comment=*/"//");
+    return std::make_unique<TextFileHandler>(/*Comment=*/"//");
   if (FilesType == "ii")
-    return new TextFileHandler(/*Comment=*/"//");
+    return std::make_unique<TextFileHandler>(/*Comment=*/"//");
   if (FilesType == "cui")
-    return new TextFileHandler(/*Comment=*/"//");
+    return std::make_unique<TextFileHandler>(/*Comment=*/"//");
   // TODO: `.d` should be eventually removed once `-M` and its variants are
   // handled properly in offload compilation.
   if (FilesType == "d")
-    return new TextFileHandler(/*Comment=*/"#");
+    return std::make_unique<TextFileHandler>(/*Comment=*/"#");
   if (FilesType == "ll")
-    return new TextFileHandler(/*Comment=*/";");
+    return std::make_unique<TextFileHandler>(/*Comment=*/";");
   if (FilesType == "bc")
-    return new BinaryFileHandler();
+    return std::make_unique<BinaryFileHandler>();
   if (FilesType == "s")
-    return new TextFileHandler(/*Comment=*/"#");
+    return std::make_unique<TextFileHandler>(/*Comment=*/"#");
   if (FilesType == "o")
     return CreateObjectFileHandler(FirstInput);
   if (FilesType == "gch")
-    return new BinaryFileHandler();
+    return std::make_unique<BinaryFileHandler>();
   if (FilesType == "ast")
-    return new BinaryFileHandler();
+    return std::make_unique<BinaryFileHandler>();
 
-  errs() << "error: invalid file type specified.\n";
-  return nullptr;
+  return createStringError(errc::invalid_argument,
+                           "'" + FilesType + "': invalid file type specified");
 }
 
 /// Bundle the files. Return true if an error was found.
-static bool BundleFiles() {
+static Error BundleFiles() {
   std::error_code EC;
 
   // Create output file.
   raw_fd_ostream OutputFile(OutputFileNames.front(), EC, sys::fs::OF_None);
-
-  if (EC) {
-    errs() << "error: Can't open file " << OutputFileNames.front() << ".\n";
-    return true;
-  }
+  if (EC)
+    return createFileError(OutputFileNames.front(), EC);
 
   // Open input files.
   SmallVector<std::unique_ptr<MemoryBuffer>, 8u> InputBuffers;
@@ -673,61 +676,62 @@ static bool BundleFiles() {
   for (auto &I : InputFileNames) {
     ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
         MemoryBuffer::getFileOrSTDIN(I);
-    if (std::error_code EC = CodeOrErr.getError()) {
-      errs() << "error: Can't open file " << I << ": " << EC.message() << "\n";
-      return true;
-    }
-    InputBuffers.emplace_back(std::move(CodeOrErr.get()));
+    if (std::error_code EC = CodeOrErr.getError())
+      return createFileError(I, EC);
+    InputBuffers.emplace_back(std::move(*CodeOrErr));
   }
 
   // Get the file handler. We use the host buffer as reference.
   assert(HostInputIndex != ~0u && "Host input index undefined??");
-  std::unique_ptr<FileHandler> FH;
-  FH.reset(CreateFileHandler(*InputBuffers[HostInputIndex].get()));
+  Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
+      CreateFileHandler(*InputBuffers[HostInputIndex]);
+  if (!FileHandlerOrErr)
+    return FileHandlerOrErr.takeError();
 
-  // Quit if we don't have a handler.
-  if (!FH.get())
-    return true;
+  std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
+  assert(FH);
 
   // Write header.
-  FH.get()->WriteHeader(OutputFile, InputBuffers);
+  if (Error Err = FH->WriteHeader(OutputFile, InputBuffers))
+    return Err;
 
   // Write all bundles along with the start/end markers. If an error was found
   // writing the end of the bundle component, abort the bundle writing.
   auto Input = InputBuffers.begin();
   for (auto &Triple : TargetNames) {
-    FH.get()->WriteBundleStart(OutputFile, Triple);
-    FH.get()->WriteBundle(OutputFile, *Input->get());
-    if (FH.get()->WriteBundleEnd(OutputFile, Triple))
-      return true;
+    if (Error Err = FH->WriteBundleStart(OutputFile, Triple))
+      return Err;
+    if (Error Err = FH->WriteBundle(OutputFile, **Input))
+      return Err;
+    if (Error Err = FH->WriteBundleEnd(OutputFile, Triple))
+      return Err;
     ++Input;
   }
-  return false;
+  return Error::success();
 }
 
 // Unbundle the files. Return true if an error was found.
-static bool UnbundleFiles() {
+static Error UnbundleFiles() {
   // Open Input file.
   ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
       MemoryBuffer::getFileOrSTDIN(InputFileNames.front());
-  if (std::error_code EC = CodeOrErr.getError()) {
-    errs() << "error: Can't open file " << InputFileNames.front() << ": "
-           << EC.message() << "\n";
-    return true;
-  }
+  if (std::error_code EC = CodeOrErr.getError())
+    return createFileError(InputFileNames.front(), EC);
 
-  MemoryBuffer &Input = *CodeOrErr.get();
+  MemoryBuffer &Input = **CodeOrErr;
 
   // Select the right files handler.
-  std::unique_ptr<FileHandler> FH;
-  FH.reset(CreateFileHandler(Input));
+  Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
+      CreateFileHandler(Input);
+  if (!FileHandlerOrErr)
+    return FileHandlerOrErr.takeError();
 
-  // Quit if we don't have a handler.
-  if (!FH.get())
-    return true;
+  std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
+  assert(FH);
 
   // Read the header of the bundled file.
-  FH.get()->ReadHeader(Input);
+  if (Error Err = FH->ReadHeader(Input))
+    return Err;
 
   // Create a work list that consist of the map triple/output file.
   StringMap<StringRef> Worklist;
@@ -741,29 +745,32 @@ static bool UnbundleFiles() {
   // assume the file is meant for the host target.
   bool FoundHostBundle = false;
   while (!Worklist.empty()) {
-    StringRef CurTriple = FH.get()->ReadBundleStart(Input);
+    Expected<Optional<StringRef>> CurTripleOrErr = FH->ReadBundleStart(Input);
+    if (!CurTripleOrErr)
+      return CurTripleOrErr.takeError();
 
     // We don't have more bundles.
-    if (CurTriple.empty())
+    if (!*CurTripleOrErr)
       break;
 
+    StringRef CurTriple = **CurTripleOrErr;
+    assert(!CurTriple.empty());
+
     auto Output = Worklist.find(CurTriple);
     // The file may have more bundles for other targets, that we don't care
     // about. Therefore, move on to the next triple
-    if (Output == Worklist.end()) {
+    if (Output == Worklist.end())
       continue;
-    }
 
     // Check if the output file can be opened and copy the bundle to it.
     std::error_code EC;
     raw_fd_ostream OutputFile(Output->second, EC, sys::fs::OF_None);
-    if (EC) {
-      errs() << "error: Can't open file " << Output->second << ": "
-             << EC.message() << "\n";
-      return true;
-    }
-    FH.get()->ReadBundle(OutputFile, Input);
-    FH.get()->ReadBundleEnd(Input);
+    if (EC)
+      return createFileError(Output->second, EC);
+    if (Error Err = FH->ReadBundle(OutputFile, Input))
+      return Err;
+    if (Error Err = FH->ReadBundleEnd(Input))
+      return Err;
     Worklist.erase(Output);
 
     // Record if we found the host bundle.
@@ -777,38 +784,31 @@ static bool UnbundleFiles() {
     for (auto &E : Worklist) {
       std::error_code EC;
       raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
-      if (EC) {
-        errs() << "error: Can't open file " << E.second << ": " << EC.message()
-               << "\n";
-        return true;
-      }
+      if (EC)
+        return createFileError(E.second, EC);
 
       // If this entry has a host kind, copy the input file to the output file.
       if (hasHostKind(E.first()))
         OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
     }
-    return false;
+    return Error::success();
   }
 
   // If we found elements, we emit an error if none of those were for the host
   // in case host bundle name was provided in command line.
-  if (!FoundHostBundle && HostInputIndex != ~0u) {
-    errs() << "error: Can't find bundle for the host target\n";
-    return true;
-  }
+  if (!FoundHostBundle && HostInputIndex != ~0u)
+    return createStringError(inconvertibleErrorCode(),
+                             "Can't find bundle for the host target");
 
   // If we still have any elements in the worklist, create empty files for them.
   for (auto &E : Worklist) {
     std::error_code EC;
     raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
-    if (EC) {
-      errs() << "error: Can't open file " << E.second << ": "  << EC.message()
-             << "\n";
-      return true;
-    }
+    if (EC)
+      return createFileError(E.second, EC);
   }
 
-  return false;
+  return Error::success();
 }
 
 static void PrintVersion(raw_ostream &OS) {
@@ -832,26 +832,36 @@ int main(int argc, const char **argv) {
     return 0;
   }
 
+  auto reportError = [argv](Error E) {
+    logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
+  };
+
   bool Error = false;
   if (Unbundle) {
     if (InputFileNames.size() != 1) {
       Error = true;
-      errs() << "error: only one input file supported in unbundling mode.\n";
+      reportError(createStringError(
+          errc::invalid_argument,
+          "only one input file supported in unbundling mode"));
     }
     if (OutputFileNames.size() != TargetNames.size()) {
       Error = true;
-      errs() << "error: number of output files and targets should match in "
-                "unbundling mode.\n";
+      reportError(createStringError(errc::invalid_argument,
+                                    "number of output files and targets should "
+                                    "match in unbundling mode"));
     }
   } else {
     if (OutputFileNames.size() != 1) {
       Error = true;
-      errs() << "error: only one output file supported in bundling mode.\n";
+      reportError(createStringError(
+          errc::invalid_argument,
+          "only one output file supported in bundling mode"));
     }
     if (InputFileNames.size() != TargetNames.size()) {
       Error = true;
-      errs() << "error: number of input files and targets should match in "
-                "bundling mode.\n";
+      reportError(createStringError(
+          errc::invalid_argument,
+          "number of input files and targets should match in bundling mode"));
     }
   }
 
@@ -877,13 +887,15 @@ int main(int argc, const char **argv) {
 
     if (!KindIsValid || !TripleIsValid) {
       Error = true;
-      errs() << "error: invalid target '" << Target << "'";
 
+      SmallVector<char, 128u> Buf;
+      raw_svector_ostream Msg(Buf);
+      Msg << "invalid target '" << Target << "'";
       if (!KindIsValid)
-        errs() << ", unknown offloading kind '" << Kind << "'";
+        Msg << ", unknown offloading kind '" << Kind << "'";
       if (!TripleIsValid)
-        errs() << ", unknown target triple '" << Triple << "'";
-      errs() << ".\n";
+        Msg << ", unknown target triple '" << Triple << "'";
+      reportError(createStringError(errc::invalid_argument, Msg.str()));
     }
 
     if (KindIsValid && Kind == "host") {
@@ -899,8 +911,9 @@ int main(int argc, const char **argv) {
   // treat missing host triple as error if we do unbundling.
   if ((Unbundle && HostTargetNum > 1) || (!Unbundle && HostTargetNum != 1)) {
     Error = true;
-    errs() << "error: expecting exactly one host target but got "
-           << HostTargetNum << ".\n";
+    reportError(createStringError(errc::invalid_argument,
+                                  "expecting exactly one host target but got " +
+                                      Twine(HostTargetNum)));
   }
 
   if (Error)
@@ -910,5 +923,9 @@ int main(int argc, const char **argv) {
   // tools.
   BundlerExecutable = sys::fs::getMainExecutable(argv[0], &BundlerExecutable);
 
-  return Unbundle ? UnbundleFiles() : BundleFiles();
+  if (llvm::Error Err = Unbundle ? UnbundleFiles() : BundleFiles()) {
+    reportError(std::move(Err));
+    return 1;
+  }
+  return 0;
 }


        


More information about the cfe-commits mailing list