COFF: Define an error category for the linker.

Instead of returning non-categorized errors, return categorized errors.
All uses of make_dynamic_error_code are removed.

Because we don't have error reporting mechanism, I just chose to print out
error messages to stderr, and then return an error object. Not sure if
that's the right thing to do, but at least it seems practical.

http://reviews.llvm.org/D10129

llvm-svn: 238714
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 8f24885..9e12338 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -10,7 +10,6 @@
 #include "Chunks.h"
 #include "InputFiles.h"
 #include "Writer.h"
-#include "lld/Core/Error.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Support/COFF.h"
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 9e2c89c..5ffc89a 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -13,7 +13,6 @@
 #include "Memory.h"
 #include "SymbolTable.h"
 #include "Writer.h"
-#include "lld/Core/Error.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringSwitch.h"
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index c1e4a62..0f58a33 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -14,8 +14,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "Driver.h"
+#include "Error.h"
 #include "Memory.h"
-#include "lld/Core/Error.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -24,7 +24,6 @@
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/Option.h"
 #include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Format.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/raw_ostream.h"
@@ -46,8 +45,10 @@
                           .Case("x64", IMAGE_FILE_MACHINE_AMD64)
                           .Case("x86", IMAGE_FILE_MACHINE_I386)
                           .Default(IMAGE_FILE_MACHINE_UNKNOWN);
-    if (MT == IMAGE_FILE_MACHINE_UNKNOWN)
-      return make_dynamic_error_code("unknown /machine argument" + S);
+    if (MT == IMAGE_FILE_MACHINE_UNKNOWN) {
+      llvm::errs() << "unknown /machine argument" << S << "\n";
+      return make_error_code(LLDError::InvalidOption);
+    }
     return MT;
   }
   return IMAGE_FILE_MACHINE_UNKNOWN;
@@ -57,10 +58,14 @@
 std::error_code parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) {
   StringRef S1, S2;
   std::tie(S1, S2) = Arg.split(',');
-  if (S1.getAsInteger(0, *Addr))
-    return make_dynamic_error_code(Twine("invalid number: ") + S1);
-  if (Size && !S2.empty() && S2.getAsInteger(0, *Size))
-    return make_dynamic_error_code(Twine("invalid number: ") + S2);
+  if (S1.getAsInteger(0, *Addr)) {
+    llvm::errs() << "invalid number: " << S1 << "\n";
+    return make_error_code(LLDError::InvalidOption);
+  }
+  if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) {
+    llvm::errs() << "invalid number: " << S2 << "\n";
+    return make_error_code(LLDError::InvalidOption);
+  }
   return std::error_code();
 }
 
@@ -69,11 +74,15 @@
 std::error_code parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
   StringRef S1, S2;
   std::tie(S1, S2) = Arg.split('.');
-  if (S1.getAsInteger(0, *Major))
-    return make_dynamic_error_code(Twine("invalid number: ") + S1);
+  if (S1.getAsInteger(0, *Major)) {
+    llvm::errs() << "invalid number: " << S1 << "\n";
+    return make_error_code(LLDError::InvalidOption);
+  }
   *Minor = 0;
-  if (!S2.empty() && S2.getAsInteger(0, *Minor))
-    return make_dynamic_error_code(Twine("invalid number: ") + S2);
+  if (!S2.empty() && S2.getAsInteger(0, *Minor)) {
+    llvm::errs() << "invalid number: " << S2 << "\n";
+    return make_error_code(LLDError::InvalidOption);
+  }
   return std::error_code();
 }
 
@@ -93,8 +102,10 @@
     .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)
     .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
     .Default(IMAGE_SUBSYSTEM_UNKNOWN);
-  if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN)
-    return make_dynamic_error_code(Twine("unknown subsystem: ") + SysStr);
+  if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) {
+    llvm::errs() << "unknown subsystem: " << SysStr << "\n";
+    return make_error_code(LLDError::InvalidOption);
+  }
   if (!Ver.empty())
     if (auto EC = parseVersion(Ver, Major, Minor))
       return EC;
@@ -132,13 +143,11 @@
   std::unique_ptr<llvm::opt::InputArgList> Args(
       Table.ParseArgs(&Argv[1], &Argv[Argc], MissingIndex, MissingCount));
   if (MissingCount) {
-    std::string S;
-    llvm::raw_string_ostream OS(S);
-    OS << llvm::format("missing arg value for \"%s\", expected %d argument%s.",
-                       Args->getArgString(MissingIndex), MissingCount,
-                       (MissingCount == 1 ? "" : "s"));
-    OS.flush();
-    return make_dynamic_error_code(StringRef(S));
+    llvm::errs() << "missing arg value for \""
+                 << Args->getArgString(MissingIndex)
+                 << "\", expected " << MissingCount
+                 << (MissingCount == 1 ? " argument.\n" : " arguments.\n");
+    return make_error_code(LLDError::InvalidOption);
   }
   for (auto *Arg : Args->filtered(OPT_UNKNOWN))
     llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
diff --git a/lld/COFF/Error.h b/lld/COFF/Error.h
new file mode 100644
index 0000000..5607dc5
--- /dev/null
+++ b/lld/COFF/Error.h
@@ -0,0 +1,54 @@
+//===- Error.h ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_ERROR_H
+#define LLD_COFF_ERROR_H
+
+#include <string>
+#include <system_error>
+#include "llvm/Support/ErrorHandling.h"
+
+namespace lld {
+namespace coff {
+
+enum class LLDError {
+  InvalidOption = 1,
+  InvalidFile,
+  BrokenFile,
+  DuplicateSymbols,
+};
+
+class LLDErrorCategory : public std::error_category {
+public:
+  const char *name() const override { return "lld"; }
+
+  std::string message(int EV) const override {
+    switch (static_cast<LLDError>(EV)) {
+    case LLDError::InvalidOption:
+      return "Invalid option";
+    case LLDError::InvalidFile:
+      return "Invalid file";
+    case LLDError::BrokenFile:
+      return "Broken file";
+    case LLDError::DuplicateSymbols:
+      return "Duplicate symbols";
+    }
+    llvm_unreachable("unknown error");
+  }
+};
+
+inline std::error_code make_error_code(LLDError Err) {
+  static LLDErrorCategory C;
+  return std::error_code(static_cast<int>(Err), C);
+}
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 88406be..6737e0f 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -8,9 +8,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "Chunks.h"
+#include "Error.h"
 #include "InputFiles.h"
 #include "Writer.h"
-#include "lld/Core/Error.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Support/COFF.h"
@@ -93,7 +93,8 @@
     Bin.release();
     COFFObj.reset(Obj);
   } else {
-    return make_dynamic_error_code(getName() + " is not a COFF file.");
+    llvm::errs() << getName() << " is not a COFF file.\n";
+    return make_error_code(LLDError::InvalidFile);
   }
 
   // Read section and symbol tables.
@@ -113,12 +114,16 @@
   for (uint32_t I = 1; I < NumSections + 1; ++I) {
     const coff_section *Sec;
     StringRef Name;
-    if (auto EC = COFFObj->getSection(I, Sec))
-      return make_dynamic_error_code(Twine("getSection failed: ") + Name +
-                                     ": " + EC.message());
-    if (auto EC = COFFObj->getSectionName(Sec, Name))
-      return make_dynamic_error_code(Twine("getSectionName failed: ") + Name +
-                                     ": " + EC.message());
+    if (auto EC = COFFObj->getSection(I, Sec)) {
+      llvm::errs() << "getSection failed: " << Name << ": "
+                   << EC.message() << "\n";
+      return make_error_code(LLDError::BrokenFile);
+    }
+    if (auto EC = COFFObj->getSectionName(Sec, Name)) {
+      llvm::errs() << "getSectionName failed: " << Name << ": "
+                   << EC.message() << "\n";
+      return make_error_code(LLDError::BrokenFile);
+    }
     if (Name == ".drectve") {
       ArrayRef<uint8_t> Data;
       COFFObj->getSectionContents(Sec, Data);
@@ -144,16 +149,20 @@
   for (uint32_t I = 0; I < NumSymbols; ++I) {
     // Get a COFFSymbolRef object.
     auto SymOrErr = COFFObj->getSymbol(I);
-    if (auto EC = SymOrErr.getError())
-      return make_dynamic_error_code("broken object file: " + getName() +
-                                     ": " + EC.message());
+    if (auto EC = SymOrErr.getError()) {
+      llvm::errs() << "broken object file: " << getName() << ": "
+                   << EC.message() << "\n";
+      return make_error_code(LLDError::BrokenFile);
+    }
     COFFSymbolRef Sym = SymOrErr.get();
 
     // Get a symbol name.
     StringRef SymbolName;
-    if (auto EC = COFFObj->getSymbolName(Sym, SymbolName))
-      return make_dynamic_error_code("broken object file: " + getName() +
-                                     ": " + EC.message());
+    if (auto EC = COFFObj->getSymbolName(Sym, SymbolName)) {
+      llvm::errs() << "broken object file: " << getName() << ": "
+                   << EC.message() << "\n";
+      return make_error_code(LLDError::BrokenFile);
+    }
     // Skip special symbols.
     if (SymbolName == "@comp.id" || SymbolName == "@feat.00")
       continue;
@@ -210,8 +219,10 @@
   const auto *Hdr = reinterpret_cast<const coff_import_header *>(Buf);
 
   // Check if the total size is valid.
-  if (End - Buf != sizeof(*Hdr) + Hdr->SizeOfData)
-    return make_dynamic_error_code("broken import library");
+  if (End - Buf != sizeof(*Hdr) + Hdr->SizeOfData) {
+    llvm::errs() << "broken import library\n";
+    return make_error_code(LLDError::BrokenFile);
+  }
 
   // Read names and create an __imp_ symbol.
   StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr)));
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index da1aa84..a7298f1 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -9,8 +9,8 @@
 
 #include "Config.h"
 #include "Driver.h"
+#include "Error.h"
 #include "SymbolTable.h"
-#include "lld/Core/Error.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -115,8 +115,10 @@
   int comp = Existing->compare(New);
   if (comp < 0)
     Sym->Body = New;
-  if (comp == 0)
-    return make_dynamic_error_code(Twine("duplicate symbol: ") + Name);
+  if (comp == 0) {
+    llvm::errs() << "duplicate symbol: " << Name << "\n";
+    return make_error_code(LLDError::DuplicateSymbols);
+  }
 
   // If we have an Undefined symbol for a Lazy symbol, we need
   // to read an archive member to replace the Lazy symbol with
@@ -180,7 +182,8 @@
       return EC;
     return StringRef(E[1]);
   }
-  return make_dynamic_error_code("entry point must be defined");
+  llvm::errs() << "entry point must be defined\n";
+  return make_error_code(LLDError::InvalidOption);
 }
 
 std::error_code SymbolTable::addUndefined(StringRef Name) {
diff --git a/lld/COFF/Symbols.cpp b/lld/COFF/Symbols.cpp
index 8bd5e65..15f6aaa 100644
--- a/lld/COFF/Symbols.cpp
+++ b/lld/COFF/Symbols.cpp
@@ -7,9 +7,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "Error.h"
 #include "InputFiles.h"
 #include "Symbols.h"
-#include "lld/Core/Error.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -84,8 +84,10 @@
   if (Magic == file_magic::coff_import_library)
     return std::unique_ptr<InputFile>(new ImportFile(MBRef));
 
-  if (Magic != file_magic::coff_object)
-    return make_dynamic_error_code("unknown file type");
+  if (Magic != file_magic::coff_object) {
+    llvm::errs() << File->getName() << ": unknown file type\n";
+    return make_error_code(LLDError::InvalidFile);
+  }
 
   std::unique_ptr<InputFile> Obj(new ObjectFile(MBRef));
   Obj->setParentName(File->getName());
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index e38f65a..e049c13 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -9,7 +9,6 @@
 
 #include "Config.h"
 #include "Writer.h"
-#include "lld/Core/Error.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/ADT/STLExtras.h"
@@ -356,9 +355,10 @@
 
 std::error_code Writer::openFile(StringRef Path) {
   if (auto EC = FileOutputBuffer::create(Path, FileSize, Buffer,
-                                         FileOutputBuffer::F_executable))
-    return make_dynamic_error_code(Twine("Failed to open ") + Path + ": " +
-                                   EC.message());
+                                         FileOutputBuffer::F_executable)) {
+    llvm::errs() << "failed to open " << Path << ": " << EC.message() << "\n";
+    return EC;
+  }
   return std::error_code();
 }