Index: COFF/CMakeLists.txt =================================================================== --- COFF/CMakeLists.txt +++ COFF/CMakeLists.txt @@ -7,6 +7,7 @@ DLL.cpp Driver.cpp DriverUtils.cpp + Error.cpp ICF.cpp InputFiles.cpp ModuleDef.cpp Index: COFF/Chunks.cpp =================================================================== --- COFF/Chunks.cpp +++ COFF/Chunks.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "Chunks.h" +#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "llvm/Object/COFF.h" @@ -60,7 +61,7 @@ case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break; case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break; default: - llvm::report_fatal_error("Unsupported relocation type"); + error("Unsupported relocation type"); } } @@ -75,7 +76,7 @@ case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break; case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break; default: - llvm::report_fatal_error("Unsupported relocation type"); + error("Unsupported relocation type"); } } @@ -119,7 +120,7 @@ case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break; case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break; default: - llvm::report_fatal_error("Unsupported relocation type"); + error("Unsupported relocation type"); } } Index: COFF/Driver.h =================================================================== --- COFF/Driver.h +++ COFF/Driver.h @@ -36,27 +36,24 @@ class InputFile; // Entry point of the COFF linker. -bool link(llvm::ArrayRef Args); +void link(llvm::ArrayRef Args); class ArgParser { public: ArgParser() : Alloc(AllocAux) {} // Parses command line options. - ErrorOr parse(llvm::ArrayRef Args); + llvm::opt::InputArgList parse(llvm::ArrayRef Args); // Concatenate LINK environment varirable and given arguments and parse them. - ErrorOr parseLINK(llvm::ArrayRef Args); + llvm::opt::InputArgList parseLINK(llvm::ArrayRef Args); // Tokenizes a given string and then parses as command line options. - ErrorOr parse(StringRef S) { - return parse(tokenize(S)); - } + llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } private: std::vector tokenize(StringRef S); - ErrorOr> - replaceResponseFiles(std::vector); + std::vector replaceResponseFiles(std::vector); llvm::BumpPtrAllocator AllocAux; llvm::BumpPtrStringSaver Alloc; @@ -65,10 +62,10 @@ class LinkerDriver { public: LinkerDriver() : Alloc(AllocAux) {} - bool link(llvm::ArrayRef Args); + void link(llvm::ArrayRef Args); // Used by the resolver to parse .drectve section contents. - std::error_code parseDirectives(StringRef S); + void parseDirectives(StringRef S); private: llvm::BumpPtrAllocator AllocAux; @@ -77,7 +74,7 @@ SymbolTable Symtab; // Opens a file. Path has to be resolved already. - ErrorOr openFile(StringRef Path); + MemoryBufferRef openFile(StringRef Path); // Searches a file from search paths. Optional findFile(StringRef Filename); @@ -110,57 +107,55 @@ std::vector> OwningMBs; }; -std::error_code parseModuleDefs(MemoryBufferRef MB, - llvm::BumpPtrStringSaver *Alloc); -std::error_code writeImportLibrary(); +void parseModuleDefs(MemoryBufferRef MB, llvm::BumpPtrStringSaver *Alloc); +void writeImportLibrary(); // Functions below this line are defined in DriverUtils.cpp. void printHelp(const char *Argv0); // For /machine option. -ErrorOr getMachineType(StringRef Arg); +MachineTypes getMachineType(StringRef Arg); StringRef machineToStr(MachineTypes MT); // Parses a string in the form of "[,]". -std::error_code parseNumbers(StringRef Arg, uint64_t *Addr, - uint64_t *Size = nullptr); +void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr); // Parses a string in the form of "[.]". // Minor's default value is 0. -std::error_code parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); +void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); // Parses a string in the form of "[,[.]]". -std::error_code parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, - uint32_t *Major, uint32_t *Minor); +void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, + uint32_t *Minor); -std::error_code parseAlternateName(StringRef); -std::error_code parseMerge(StringRef); +void parseAlternateName(StringRef); +void parseMerge(StringRef); // Parses a string in the form of "EMBED[,=]|NO". -std::error_code parseManifest(StringRef Arg); +void parseManifest(StringRef Arg); // Parses a string in the form of "level=|uiAccess=" -std::error_code parseManifestUAC(StringRef Arg); +void parseManifestUAC(StringRef Arg); // Create a resource file containing a manifest XML. -ErrorOr> createManifestRes(); -std::error_code createSideBySideManifest(); +std::unique_ptr createManifestRes(); +void createSideBySideManifest(); // Used for dllexported symbols. -ErrorOr parseExport(StringRef Arg); -std::error_code fixupExports(); +Export parseExport(StringRef Arg); +void fixupExports(); void assignExportOrdinals(); // Parses a string in the form of "key=value" and check // if value matches previous values for the key. // This feature used in the directive section to reject // incompatible objects. -std::error_code checkFailIfMismatch(StringRef Arg); +void checkFailIfMismatch(StringRef Arg); // Convert Windows resource files (.res files) to a .obj file // using cvtres.exe. -ErrorOr> +std::unique_ptr convertResToCOFF(const std::vector &MBs); void touchFile(StringRef Path); Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -43,7 +43,7 @@ Configuration *Config; LinkerDriver *Driver; -bool link(llvm::ArrayRef Args) { +void link(llvm::ArrayRef Args) { auto C = make_unique(); Config = C.get(); auto D = make_unique(); @@ -60,11 +60,10 @@ // Opens a file. Path has to be resolved already. // Newly created memory buffers are owned by this driver. -ErrorOr LinkerDriver::openFile(StringRef Path) { +MemoryBufferRef LinkerDriver::openFile(StringRef Path) { auto MBOrErr = MemoryBuffer::getFile(Path); - if (auto EC = MBOrErr.getError()) - return EC; - std::unique_ptr MB = std::move(MBOrErr.get()); + error(MBOrErr, Twine("Could not open ") + Path); + std::unique_ptr &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); OwningMBs.push_back(std::move(MB)); // take ownership return MBRef; @@ -84,46 +83,35 @@ // Parses .drectve section contents and returns a list of files // specified by /defaultlib. -std::error_code -LinkerDriver::parseDirectives(StringRef S) { - auto ArgsOrErr = Parser.parse(S); - if (auto EC = ArgsOrErr.getError()) - return EC; - llvm::opt::InputArgList Args = std::move(ArgsOrErr.get()); +void LinkerDriver::parseDirectives(StringRef S) { + llvm::opt::InputArgList Args = Parser.parse(S); for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_alternatename: - if (auto EC = parseAlternateName(Arg->getValue())) - return EC; + parseAlternateName(Arg->getValue()); break; case OPT_defaultlib: if (Optional Path = findLib(Arg->getValue())) { - ErrorOr MBOrErr = openFile(*Path); - if (auto EC = MBOrErr.getError()) - return EC; - Symtab.addFile(createFile(MBOrErr.get())); + MemoryBufferRef MB = openFile(*Path); + Symtab.addFile(createFile(MB)); } break; case OPT_export: { - ErrorOr E = parseExport(Arg->getValue()); - if (auto EC = E.getError()) - return EC; - if (Config->Machine == I386 && E->ExtName.startswith("_")) - E->ExtName = E->ExtName.substr(1); - Config->Exports.push_back(E.get()); + Export E = parseExport(Arg->getValue()); + if (Config->Machine == I386 && E.ExtName.startswith("_")) + E.ExtName = E.ExtName.substr(1); + Config->Exports.push_back(E); break; } case OPT_failifmismatch: - if (auto EC = checkFailIfMismatch(Arg->getValue())) - return EC; + checkFailIfMismatch(Arg->getValue()); break; case OPT_incl: addUndefined(Arg->getValue()); break; case OPT_merge: - if (auto EC = parseMerge(Arg->getValue())) - return EC; + parseMerge(Arg->getValue()); break; case OPT_nodefaultlib: Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); @@ -131,11 +119,9 @@ case OPT_throwingnew: break; default: - llvm::errs() << Arg->getSpelling() << " is not allowed in .drectve\n"; - return make_error_code(LLDError::InvalidOption); + error(Twine(Arg->getSpelling()) + " is not allowed in .drectve"); } } - return std::error_code(); } // Find file from search paths. You can omit ".obj", this function takes @@ -253,7 +239,7 @@ return Config->DLL ? 0x10000000 : 0x400000; } -bool LinkerDriver::link(llvm::ArrayRef ArgsArr) { +void LinkerDriver::link(llvm::ArrayRef ArgsArr) { // Needed for LTO. llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargets(); @@ -265,26 +251,20 @@ // If the first command line argument is "/lib", link.exe acts like lib.exe. // We call our own implementation of lib.exe that understands bitcode files. if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) - return llvm::libDriverMain(ArgsArr.slice(1)) == 0; + if (llvm::libDriverMain(ArgsArr.slice(1)) != 0) + error("lib failed"); // Parse command line options. - auto ArgsOrErr = Parser.parseLINK(ArgsArr.slice(1)); - if (auto EC = ArgsOrErr.getError()) { - llvm::errs() << EC.message() << "\n"; - return false; - } - llvm::opt::InputArgList Args = std::move(ArgsOrErr.get()); + llvm::opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1)); // Handle /help if (Args.hasArg(OPT_help)) { printHelp(ArgsArr[0]); - return true; + return; } - if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end()) { - llvm::errs() << "no input files.\n"; - return false; - } + if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end()) + error("no input files."); // Construct search path list. SearchPaths.push_back(""); @@ -310,10 +290,8 @@ // Handle /noentry if (Args.hasArg(OPT_noentry)) { - if (!Args.hasArg(OPT_dll)) { - llvm::errs() << "/noentry must be specified with /dll\n"; - return false; - } + if (!Args.hasArg(OPT_dll)) + error("/noentry must be specified with /dll"); Config->NoEntry = true; } @@ -325,21 +303,15 @@ // Handle /fixed if (Args.hasArg(OPT_fixed)) { - if (Args.hasArg(OPT_dynamicbase)) { - llvm::errs() << "/fixed must not be specified with /dynamicbase\n"; - return false; - } + if (Args.hasArg(OPT_dynamicbase)) + error("/fixed must not be specified with /dynamicbase"); Config->Relocatable = false; Config->DynamicBase = false; } // Handle /machine - if (auto *Arg = Args.getLastArg(OPT_machine)) { - ErrorOr MTOrErr = getMachineType(Arg->getValue()); - if (MTOrErr.getError()) - return false; - Config->Machine = MTOrErr.get(); - } + if (auto *Arg = Args.getLastArg(OPT_machine)) + Config->Machine = getMachineType(Arg->getValue()); // Handle /nodefaultlib: for (auto *Arg : Args.filtered(OPT_nodefaultlib)) @@ -350,54 +322,30 @@ Config->NoDefaultLibAll = true; // Handle /base - if (auto *Arg = Args.getLastArg(OPT_base)) { - if (auto EC = parseNumbers(Arg->getValue(), &Config->ImageBase)) { - llvm::errs() << "/base: " << EC.message() << "\n"; - return false; - } - } + if (auto *Arg = Args.getLastArg(OPT_base)) + parseNumbers(Arg->getValue(), &Config->ImageBase); // Handle /stack - if (auto *Arg = Args.getLastArg(OPT_stack)) { - if (auto EC = parseNumbers(Arg->getValue(), &Config->StackReserve, - &Config->StackCommit)) { - llvm::errs() << "/stack: " << EC.message() << "\n"; - return false; - } - } + if (auto *Arg = Args.getLastArg(OPT_stack)) + parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit); // Handle /heap - if (auto *Arg = Args.getLastArg(OPT_heap)) { - if (auto EC = parseNumbers(Arg->getValue(), &Config->HeapReserve, - &Config->HeapCommit)) { - llvm::errs() << "/heap: " << EC.message() << "\n"; - return false; - } - } + if (auto *Arg = Args.getLastArg(OPT_heap)) + parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit); // Handle /version - if (auto *Arg = Args.getLastArg(OPT_version)) { - if (auto EC = parseVersion(Arg->getValue(), &Config->MajorImageVersion, - &Config->MinorImageVersion)) { - llvm::errs() << "/version: " << EC.message() << "\n"; - return false; - } - } + if (auto *Arg = Args.getLastArg(OPT_version)) + parseVersion(Arg->getValue(), &Config->MajorImageVersion, + &Config->MinorImageVersion); // Handle /subsystem - if (auto *Arg = Args.getLastArg(OPT_subsystem)) { - if (auto EC = parseSubsystem(Arg->getValue(), &Config->Subsystem, - &Config->MajorOSVersion, - &Config->MinorOSVersion)) { - llvm::errs() << "/subsystem: " << EC.message() << "\n"; - return false; - } - } + if (auto *Arg = Args.getLastArg(OPT_subsystem)) + parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, + &Config->MinorOSVersion); // Handle /alternatename for (auto *Arg : Args.filtered(OPT_alternatename)) - if (parseAlternateName(Arg->getValue())) - return false; + parseAlternateName(Arg->getValue()); // Handle /include for (auto *Arg : Args.filtered(OPT_incl)) @@ -421,36 +369,25 @@ if (S != "ref" && S != "icf" && S != "noicf" && S != "lbr" && S != "nolbr" && !StringRef(S).startswith("icf=")) { - llvm::errs() << "/opt: unknown option: " << S << "\n"; - return false; + error(Twine("/opt: unknown option: ") + S); } } // Handle /failifmismatch for (auto *Arg : Args.filtered(OPT_failifmismatch)) - if (checkFailIfMismatch(Arg->getValue())) - return false; + checkFailIfMismatch(Arg->getValue()); // Handle /merge for (auto *Arg : Args.filtered(OPT_merge)) - if (parseMerge(Arg->getValue())) - return false; + parseMerge(Arg->getValue()); // Handle /manifest - if (auto *Arg = Args.getLastArg(OPT_manifest_colon)) { - if (auto EC = parseManifest(Arg->getValue())) { - llvm::errs() << "/manifest: " << EC.message() << "\n"; - return false; - } - } + if (auto *Arg = Args.getLastArg(OPT_manifest_colon)) + parseManifest(Arg->getValue()); // Handle /manifestuac - if (auto *Arg = Args.getLastArg(OPT_manifestuac)) { - if (auto EC = parseManifestUAC(Arg->getValue())) { - llvm::errs() << "/manifestuac: " << EC.message() << "\n"; - return false; - } - } + if (auto *Arg = Args.getLastArg(OPT_manifestuac)) + parseManifestUAC(Arg->getValue()); // Handle /manifestdependency if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) @@ -482,21 +419,12 @@ for (auto *Arg : Args.filtered(OPT_defaultlib)) if (Optional Path = findLib(Arg->getValue())) Paths.push_back(*Path); - for (StringRef Path : Paths) { - ErrorOr MBOrErr = openFile(Path); - if (auto EC = MBOrErr.getError()) { - llvm::errs() << "cannot open " << Path << ": " << EC.message() << "\n"; - return false; - } - MBs.push_back(MBOrErr.get()); - } + for (StringRef Path : Paths) + MBs.push_back(openFile(Path)); // Windows specific -- Create a resource file containing a manifest file. if (Config->Manifest == Configuration::Embed) { - auto MBOrErr = createManifestRes(); - if (MBOrErr.getError()) - return false; - std::unique_ptr MB = std::move(MBOrErr.get()); + std::unique_ptr MB = createManifestRes(); MBs.push_back(MB->getMemBufferRef()); OwningMBs.push_back(std::move(MB)); // take ownership } @@ -518,10 +446,7 @@ // doesn't read files that are specified by directive sections. for (MemoryBufferRef MB : MBs) Symtab.addFile(createFile(MB)); - if (auto EC = Symtab.step()) { - llvm::errs() << EC.message() << "\n"; - return false; - } + Symtab.step(); // Determine machine type and check if all object files are // for the same CPU type. Note that this needs to be done before @@ -534,12 +459,9 @@ Config->Machine = MT; continue; } - if (Config->Machine != MT) { - llvm::errs() << File->getShortName() << ": machine type " - << machineToStr(MT) << " conflicts with " - << machineToStr(Config->Machine) << "\n"; - return false; - } + if (Config->Machine != MT) + error(Twine(File->getShortName()) + ": machine type " + machineToStr(MT) + + " conflicts with " + machineToStr(Config->Machine)); } if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { llvm::errs() << "warning: /machine is not specified. x64 is assumed.\n"; @@ -548,10 +470,7 @@ // Windows specific -- Convert Windows resource files to a COFF file. if (!Resources.empty()) { - auto MBOrErr = convertResToCOFF(Resources); - if (MBOrErr.getError()) - return false; - std::unique_ptr MB = std::move(MBOrErr.get()); + std::unique_ptr MB = convertResToCOFF(Resources); Symtab.addFile(createFile(MB->getMemBufferRef())); OwningMBs.push_back(std::move(MB)); // take ownership } @@ -575,10 +494,8 @@ // Windows specific -- If entry point name is not given, we need to // infer that from user-defined entry name. StringRef S = findDefaultEntry(); - if (S.empty()) { - llvm::errs() << "entry point must be defined\n"; - return false; - } + if (S.empty()) + error("entry point must be defined"); Config->Entry = addUndefined(S); if (Config->Verbose) llvm::outs() << "Entry name inferred: " << S << "\n"; @@ -586,24 +503,17 @@ // Handle /export for (auto *Arg : Args.filtered(OPT_export)) { - ErrorOr E = parseExport(Arg->getValue()); - if (E.getError()) - return false; - if (Config->Machine == I386 && !E->Name.startswith("_@?")) - E->Name = mangle(E->Name); - Config->Exports.push_back(E.get()); + Export E = parseExport(Arg->getValue()); + if (Config->Machine == I386 && !E.Name.startswith("_@?")) + E.Name = mangle(E.Name); + Config->Exports.push_back(E); } // Handle /def if (auto *Arg = Args.getLastArg(OPT_deffile)) { - ErrorOr MBOrErr = openFile(Arg->getValue()); - if (auto EC = MBOrErr.getError()) { - llvm::errs() << "/def: " << EC.message() << "\n"; - return false; - } + MemoryBufferRef MB = openFile(Arg->getValue()); // parseModuleDefs mutates Config object. - if (parseModuleDefs(MBOrErr.get(), &Alloc)) - return false; + parseModuleDefs(MB, &Alloc); } // Handle /delayload @@ -628,10 +538,7 @@ Config->LoadConfigUsed = mangle("_load_config_used"); // Read as much files as we can from directives sections. - if (auto EC = Symtab.run()) { - llvm::errs() << EC.message() << "\n"; - return false; - } + Symtab.run(); // Resolve auxiliary symbols until we get a convergence. // (Trying to resolve a symbol may trigger a Lazy symbol to load a new file. @@ -668,31 +575,22 @@ if (Symtab.queueEmpty()) break; - if (auto EC = Symtab.run()) { - llvm::errs() << EC.message() << "\n"; - return false; - } + Symtab.run(); } // Do LTO by compiling bitcode input files to a native COFF file // then link that file. - if (auto EC = Symtab.addCombinedLTOObject()) { - llvm::errs() << EC.message() << "\n"; - return false; - } + Symtab.addCombinedLTOObject(); // Make sure we have resolved all symbols. - if (Symtab.reportRemainingUndefines(/*Resolve=*/true)) - return false; + Symtab.reportRemainingUndefines(/*Resolve=*/true); // Windows specific -- if no /subsystem is given, we need to infer // that from entry point name. if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { Config->Subsystem = inferSubsystem(); - if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { - llvm::errs() << "subsystem must be defined\n"; - return false; - } + if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) + error("subsystem must be defined"); } // Handle /safeseh. @@ -700,46 +598,36 @@ for (ObjectFile *File : Symtab.ObjectFiles) { if (File->SEHCompat) continue; - llvm::errs() << "/safeseh: " << File->getName() - << " is not compatible with SEH\n"; - return false; + error(Twine("/safeseh: ") + File->getName() + + " is not compatible with SEH"); } } // Windows specific -- when we are creating a .dll file, we also // need to create a .lib file. if (!Config->Exports.empty()) { - if (fixupExports()) - return false; - if (writeImportLibrary()) - return false; + fixupExports(); + writeImportLibrary(); assignExportOrdinals(); } // Windows specific -- Create a side-by-side manifest file. if (Config->Manifest == Configuration::SideBySide) - if (createSideBySideManifest()) - return false; + createSideBySideManifest(); // Create a dummy PDB file to satisfy build sytem rules. if (auto *Arg = Args.getLastArg(OPT_pdb)) touchFile(Arg->getValue()); // Write the result. - if (auto EC = writeResult(&Symtab)) { - llvm::errs() << EC.message() << "\n"; - return false; - } + writeResult(&Symtab); // Create a symbol map file containing symbol VAs and their names // to help debugging. if (auto *Arg = Args.getLastArg(OPT_lldmap)) { std::error_code EC; llvm::raw_fd_ostream Out(Arg->getValue(), EC, OpenFlags::F_Text); - if (EC) { - llvm::errs() << EC.message() << "\n"; - return false; - } + error(EC, "Could not create the symbol map"); Symtab.printMap(Out); } // Call exit to avoid calling destructors. Index: COFF/DriverUtils.cpp =================================================================== --- COFF/DriverUtils.cpp +++ COFF/DriverUtils.cpp @@ -50,13 +50,9 @@ void add(Twine S) { Args.push_back(Saver.save(S)); } void add(const char *S) { Args.push_back(Saver.save(S)); } - std::error_code run() { + void run() { ErrorOr ExeOrErr = llvm::sys::findProgramByName(Prog); - if (auto EC = ExeOrErr.getError()) { - llvm::errs() << "unable to find " << Prog << " in PATH: " - << EC.message() << "\n"; - return make_error_code(LLDError::InvalidOption); - } + error(ExeOrErr, Twine("unable to find ") + Prog + " in PATH: "); const char *Exe = Saver.save(ExeOrErr.get()); Args.insert(Args.begin(), Exe); Args.push_back(nullptr); @@ -64,10 +60,8 @@ for (const char *S : Args) if (S) llvm::errs() << S << " "; - llvm::errs() << "failed\n"; - return make_error_code(LLDError::InvalidOption); + error("failed"); } - return std::error_code(); } private: @@ -80,7 +74,7 @@ } // anonymous namespace // Returns /machine's value. -ErrorOr getMachineType(StringRef S) { +MachineTypes getMachineType(StringRef S) { MachineTypes MT = StringSwitch(S.lower()) .Case("x64", AMD64) .Case("amd64", AMD64) @@ -90,8 +84,7 @@ .Default(IMAGE_FILE_MACHINE_UNKNOWN); if (MT != IMAGE_FILE_MACHINE_UNKNOWN) return MT; - llvm::errs() << "unknown /machine argument: " << S << "\n"; - return make_error_code(LLDError::InvalidOption); + error(Twine("unknown /machine argument: ") + S); } StringRef machineToStr(MachineTypes MT) { @@ -108,40 +101,30 @@ } // Parses a string in the form of "[,]". -std::error_code parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) { +void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) { StringRef S1, S2; std::tie(S1, S2) = Arg.split(','); - 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(); + if (S1.getAsInteger(0, *Addr)) + error(Twine("invalid number: ") + S1); + if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) + error(Twine("invalid number: ") + S2); } // Parses a string in the form of "[.]". // If second number is not present, Minor is set to 0. -std::error_code parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) { +void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) { StringRef S1, S2; std::tie(S1, S2) = Arg.split('.'); - if (S1.getAsInteger(0, *Major)) { - llvm::errs() << "invalid number: " << S1 << "\n"; - return make_error_code(LLDError::InvalidOption); - } + if (S1.getAsInteger(0, *Major)) + error(Twine("invalid number: ") + S1); *Minor = 0; - if (!S2.empty() && S2.getAsInteger(0, *Minor)) { - llvm::errs() << "invalid number: " << S2 << "\n"; - return make_error_code(LLDError::InvalidOption); - } - return std::error_code(); + if (!S2.empty() && S2.getAsInteger(0, *Minor)) + error(Twine("invalid number: ") + S2); } // Parses a string in the form of "[,[.]]". -std::error_code parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, - uint32_t *Major, uint32_t *Minor) { +void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, + uint32_t *Minor) { StringRef SysStr, Ver; std::tie(SysStr, Ver) = Arg.split(','); *Sys = StringSwitch(SysStr.lower()) @@ -155,43 +138,32 @@ .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI) .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI) .Default(IMAGE_SUBSYSTEM_UNKNOWN); - if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) { - llvm::errs() << "unknown subsystem: " << SysStr << "\n"; - return make_error_code(LLDError::InvalidOption); - } + if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) + error(Twine("unknown subsystem: ") + SysStr); if (!Ver.empty()) - if (auto EC = parseVersion(Ver, Major, Minor)) - return EC; - return std::error_code(); + parseVersion(Ver, Major, Minor); } // Parse a string of the form of "=". // Results are directly written to Config. -std::error_code parseAlternateName(StringRef S) { +void parseAlternateName(StringRef S) { StringRef From, To; std::tie(From, To) = S.split('='); - if (From.empty() || To.empty()) { - llvm::errs() << "/alternatename: invalid argument: " << S << "\n"; - return make_error_code(LLDError::InvalidOption); - } + if (From.empty() || To.empty()) + error(Twine("/alternatename: invalid argument: ") + S); auto It = Config->AlternateNames.find(From); - if (It != Config->AlternateNames.end() && It->second != To) { - llvm::errs() << "/alternatename: conflicts: " << S << "\n"; - return make_error_code(LLDError::InvalidOption); - } + if (It != Config->AlternateNames.end() && It->second != To) + error(Twine("/alternatename: conflicts: ") + S); Config->AlternateNames.insert(It, std::make_pair(From, To)); - return std::error_code(); } // Parse a string of the form of "=". // Results are directly written to Config. -std::error_code parseMerge(StringRef S) { +void parseMerge(StringRef S) { StringRef From, To; std::tie(From, To) = S.split('='); - if (From.empty() || To.empty()) { - llvm::errs() << "/merge: invalid argument: " << S << "\n"; - return make_error_code(LLDError::InvalidOption); - } + if (From.empty() || To.empty()) + error(Twine("/merge: invalid argument: ") + S); auto Pair = Config->Merge.insert(std::make_pair(From, To)); bool Inserted = Pair.second; if (!Inserted) { @@ -200,41 +172,39 @@ llvm::errs() << "warning: " << S << ": already merged into " << Existing << "\n"; } - return std::error_code(); } // Parses a string in the form of "EMBED[,=]|NO". // Results are directly written to Config. -std::error_code parseManifest(StringRef Arg) { +void parseManifest(StringRef Arg) { if (Arg.equals_lower("no")) { Config->Manifest = Configuration::No; - return std::error_code(); + return; } if (!Arg.startswith_lower("embed")) - return make_error_code(LLDError::InvalidOption); + error(Twine("Invalid option ") + Arg); Config->Manifest = Configuration::Embed; Arg = Arg.substr(strlen("embed")); if (Arg.empty()) - return std::error_code(); + return; if (!Arg.startswith_lower(",id=")) - return make_error_code(LLDError::InvalidOption); + error(Twine("Invalid option ") + Arg); Arg = Arg.substr(strlen(",id=")); if (Arg.getAsInteger(0, Config->ManifestID)) - return make_error_code(LLDError::InvalidOption); - return std::error_code(); + error(Twine("Invalid option ") + Arg); } // Parses a string in the form of "level=|uiAccess=|NO". // Results are directly written to Config. -std::error_code parseManifestUAC(StringRef Arg) { +void parseManifestUAC(StringRef Arg) { if (Arg.equals_lower("no")) { Config->ManifestUAC = false; - return std::error_code(); + return; } for (;;) { Arg = Arg.ltrim(); if (Arg.empty()) - return std::error_code(); + return; if (Arg.startswith_lower("level=")) { Arg = Arg.substr(strlen("level=")); std::tie(Config->ManifestLevel, Arg) = Arg.split(" "); @@ -245,7 +215,7 @@ std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" "); continue; } - return make_error_code(LLDError::InvalidOption); + error(Twine("Invalid option ") + Arg); } } @@ -301,22 +271,16 @@ } // Create a resource file containing a manifest XML. -ErrorOr> createManifestRes() { +std::unique_ptr createManifestRes() { // Create a temporary file for the resource script file. SmallString<128> RCPath; - if (sys::fs::createTemporaryFile("tmp", "rc", RCPath)) { - llvm::errs() << "cannot create a temporary file\n"; - return make_error_code(LLDError::InvalidOption); - } + std::error_code EC = sys::fs::createTemporaryFile("tmp", "rc", RCPath); + error(EC, "cannot create a temporary file"); FileRemover RCRemover(RCPath); // Open the temporary file for writing. - std::error_code EC; llvm::raw_fd_ostream Out(RCPath, EC, sys::fs::F_Text); - if (EC) { - llvm::errs() << "failed to open " << RCPath << ": " << EC.message() << "\n"; - return make_error_code(LLDError::InvalidOption); - } + error(EC, Twine("failed to open ") + RCPath); // Write resource script to the RC file. Out << "#define LANG_ENGLISH 9\n" @@ -331,39 +295,34 @@ // Create output resource file. SmallString<128> ResPath; - if (sys::fs::createTemporaryFile("tmp", "res", ResPath)) { - llvm::errs() << "cannot create a temporary file\n"; - return make_error_code(LLDError::InvalidOption); - } + EC = sys::fs::createTemporaryFile("tmp", "res", ResPath); + error(EC, "cannot create a temporary file"); Executor E("rc.exe"); E.add("/fo"); E.add(ResPath.str()); E.add("/nologo"); E.add(RCPath.str()); - if (auto EC = E.run()) - return EC; - return MemoryBuffer::getFile(ResPath); + E.run(); + ErrorOr> Ret = MemoryBuffer::getFile(ResPath); + error(Ret, Twine("Could not open ") + ResPath); + return std::move(*Ret); } -std::error_code createSideBySideManifest() { +void createSideBySideManifest() { std::string Path = Config->ManifestFile; if (Path == "") Path = (Twine(Config->OutputFile) + ".manifest").str(); std::error_code EC; llvm::raw_fd_ostream Out(Path, EC, llvm::sys::fs::F_Text); - if (EC) { - llvm::errs() << EC.message() << "\n"; - return EC; - } + error(EC, "failed to create manifest"); Out << createManifestXml(); - return std::error_code(); } // Parse a string in the form of // "[=][,@ordinal[,NONAME]][,DATA][,PRIVATE]". // Used for parsing /export arguments. -ErrorOr parseExport(StringRef Arg) { +Export parseExport(StringRef Arg) { Export E; StringRef Rest; std::tie(E.Name, Rest) = Arg.split(","); @@ -406,22 +365,19 @@ return E; err: - llvm::errs() << "invalid /export: " << Arg << "\n"; - return make_error_code(LLDError::InvalidOption); + error(Twine("invalid /export: ") + Arg); } // Performs error checking on all /export arguments. // It also sets ordinals. -std::error_code fixupExports() { +void fixupExports() { // Symbol ordinals must be unique. std::set Ords; for (Export &E : Config->Exports) { if (E.Ordinal == 0) continue; - if (!Ords.insert(E.Ordinal).second) { - llvm::errs() << "duplicate export ordinal: " << E.Name << "\n"; - return make_error_code(LLDError::InvalidOption); - } + if (!Ords.insert(E.Ordinal).second) + error(Twine("duplicate export ordinal: ") + E.Name); } for (Export &E : Config->Exports) { @@ -462,7 +418,6 @@ [](const Export &A, const Export &B) { return A.ExtDLLName < B.ExtDLLName; }); - return std::error_code(); } void assignExportOrdinals() { @@ -477,31 +432,26 @@ // Parses a string in the form of "key=value" and check // if value matches previous values for the same key. -std::error_code checkFailIfMismatch(StringRef Arg) { +void checkFailIfMismatch(StringRef Arg) { StringRef K, V; std::tie(K, V) = Arg.split('='); - if (K.empty() || V.empty()) { - llvm::errs() << "/failifmismatch: invalid argument: " << Arg << "\n"; - return make_error_code(LLDError::InvalidOption); - } + if (K.empty() || V.empty()) + error(Twine("/failifmismatch: invalid argument: ") + Arg); StringRef Existing = Config->MustMatch[K]; - if (!Existing.empty() && V != Existing) { - llvm::errs() << "/failifmismatch: mismatch detected: " - << Existing << " and " << V << " for key " << K << "\n"; - return make_error_code(LLDError::InvalidOption); - } + if (!Existing.empty() && V != Existing) + error(Twine("/failifmismatch: mismatch detected: ") + Existing + " and " + + V + " for key " + K); Config->MustMatch[K] = V; - return std::error_code(); } // Convert Windows resource files (.res files) to a .obj file // using cvtres.exe. -ErrorOr> +std::unique_ptr convertResToCOFF(const std::vector &MBs) { // Create an output file path. SmallString<128> Path; if (llvm::sys::fs::createTemporaryFile("resource", "obj", Path)) - return make_error_code(LLDError::InvalidOption); + error("Could not create temporary file"); // Execute cvtres.exe. Executor E("cvtres.exe"); @@ -511,9 +461,10 @@ E.add("/out:" + Path); for (MemoryBufferRef MB : MBs) E.add(MB.getBufferIdentifier()); - if (auto EC = E.run()) - return EC; - return MemoryBuffer::getFile(Path); + E.run(); + ErrorOr> Ret = MemoryBuffer::getFile(Path); + error(Ret, Twine("Could not open ") + Path); + return std::move(*Ret); } static std::string writeToTempFile(StringRef Contents) { @@ -551,7 +502,7 @@ } // Creates a .def file and runs lib.exe on it to create an import library. -std::error_code writeImportLibrary() { +void writeImportLibrary() { std::string Contents = createModuleDefinitionFile(); std::string Def = writeToTempFile(Contents); llvm::FileRemover TempFile(Def); @@ -567,13 +518,13 @@ } else { E.add("/out:" + Config->Implib); } - return E.run(); + E.run(); } void touchFile(StringRef Path) { int FD; - if (sys::fs::openFileForWrite(Path, FD, sys::fs::F_Append)) - report_fatal_error("failed to create a file"); + std::error_code EC = sys::fs::openFileForWrite(Path, FD, sys::fs::F_Append); + error(EC, "failed to create a file"); sys::Process::SafelyCloseFileDescriptor(FD); } @@ -601,16 +552,9 @@ }; // Parses a given list of options. -ErrorOr -ArgParser::parse(ArrayRef ArgsArr) { +llvm::opt::InputArgList ArgParser::parse(ArrayRef ArgsArr) { // First, replace respnose files (@-style options). - auto ArgvOrErr = replaceResponseFiles(ArgsArr); - if (auto EC = ArgvOrErr.getError()) { - llvm::errs() << "error while reading response file: " << EC.message() - << "\n"; - return EC; - } - std::vector Argv = std::move(ArgvOrErr.get()); + std::vector Argv = replaceResponseFiles(ArgsArr); // Make InputArgList from string vectors. COFFOptTable Table; @@ -618,20 +562,16 @@ unsigned MissingCount; llvm::opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount); - if (MissingCount) { - llvm::errs() << "missing arg value for \"" - << Args.getArgString(MissingIndex) << "\", expected " - << MissingCount - << (MissingCount == 1 ? " argument.\n" : " arguments.\n"); - return make_error_code(LLDError::InvalidOption); - } + if (MissingCount) + error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + + "\", expected " + Twine(MissingCount) + + (MissingCount == 1 ? " argument." : " arguments.")); for (auto *Arg : Args.filtered(OPT_UNKNOWN)) llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n"; - return std::move(Args); + return Args; } -ErrorOr -ArgParser::parseLINK(ArrayRef Args) { +llvm::opt::InputArgList ArgParser::parseLINK(ArrayRef Args) { // Concatenate LINK env and given arguments and parse them. Optional Env = Process::GetEnv("LINK"); if (!Env) @@ -650,7 +590,7 @@ // Creates a new command line by replacing options starting with '@' // character. '@' is replaced by the file's contents. -ErrorOr> +std::vector ArgParser::replaceResponseFiles(std::vector Argv) { SmallVector Tokens(Argv.data(), Argv.data() + Argv.size()); BumpPtrStringSaver Saver(AllocAux); Index: COFF/Error.h =================================================================== --- COFF/Error.h +++ COFF/Error.h @@ -10,42 +10,15 @@ #ifndef LLD_COFF_ERROR_H #define LLD_COFF_ERROR_H -#include -#include -#include "llvm/Support/ErrorHandling.h" +#include "lld/Core/LLVM.h" namespace lld { namespace coff { -enum class LLDError { - InvalidOption = 1, - InvalidFile, - BrokenFile, - DuplicateSymbols, -}; - -class LLDErrorCategory : public std::error_category { -public: - const char *name() const LLVM_NOEXCEPT override { return "lld"; } - - std::string message(int EV) const override { - switch (static_cast(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(Err), C); +LLVM_ATTRIBUTE_NORETURN void error(const Twine &Msg); +void error(std::error_code EC, const Twine &Prefix); +template void error(const ErrorOr &V, const Twine &Prefix) { + error(V.getError(), Prefix); } } // namespace coff Index: COFF/Error.cpp =================================================================== --- /dev/null +++ COFF/Error.cpp @@ -0,0 +1,29 @@ +//===- Error.cpp ----------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" + +namespace lld { +namespace coff { + +void error(const Twine &Msg) { + llvm::errs() << Msg << "\n"; + exit(1); +} + +void error(std::error_code EC, const Twine &Prefix) { + if (!EC) + return; + error(Prefix + ": " + EC.message()); +} +} +} Index: COFF/InputFiles.h =================================================================== --- COFF/InputFiles.h +++ COFF/InputFiles.h @@ -52,7 +52,7 @@ // Reads a file (constructors don't do that). Returns an error if a // file is broken. - virtual std::error_code parse() = 0; + virtual void parse() = 0; // Returns the CPU type this file was compiled to. virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } @@ -90,12 +90,12 @@ public: explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } - std::error_code parse() override; + void parse() override; // Returns a memory buffer for a given symbol. An empty memory buffer // is returned if we have already returned the same memory buffer. // (So that we don't instantiate same members more than once.) - ErrorOr getMember(const Archive::Symbol *Sym); + MemoryBufferRef getMember(const Archive::Symbol *Sym); std::vector &getLazySymbols() { return LazySymbols; } @@ -117,7 +117,7 @@ public: explicit ObjectFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } - std::error_code parse() override; + void parse() override; MachineTypes getMachineType() override; std::vector &getChunks() { return Chunks; } std::vector &getSymbols() override { return SymbolBodies; } @@ -140,9 +140,9 @@ std::set SEHandlers; private: - std::error_code initializeChunks(); - std::error_code initializeSymbols(); - std::error_code initializeSEH(); + void initializeChunks(); + void initializeSymbols(); + void initializeSEH(); Defined *createDefined(COFFSymbolRef Sym, const void *Aux, bool IsFirst); Undefined *createUndefined(COFFSymbolRef Sym); @@ -184,7 +184,7 @@ std::vector &getSymbols() override { return SymbolBodies; } private: - std::error_code parse() override; + void parse() override; std::vector SymbolBodies; llvm::BumpPtrAllocator Alloc; @@ -204,7 +204,7 @@ LTOModule *releaseModule() { return M.release(); } private: - std::error_code parse() override; + void parse() override; std::vector SymbolBodies; llvm::BumpPtrAllocator Alloc; Index: COFF/InputFiles.cpp =================================================================== --- COFF/InputFiles.cpp +++ COFF/InputFiles.cpp @@ -50,11 +50,10 @@ return StringRef(Res).lower(); } -std::error_code ArchiveFile::parse() { +void ArchiveFile::parse() { // Parse a MemoryBufferRef as an archive file. auto ArchiveOrErr = Archive::create(MB); - if (auto EC = ArchiveOrErr.getError()) - return EC; + error(ArchiveOrErr, "Failed to parse static library"); File = std::move(ArchiveOrErr.get()); // Allocate a buffer for Lazy objects. @@ -77,63 +76,55 @@ // are not read yet. for (const Archive::Child &Child : File->children()) Seen[Child.getChildOffset()].clear(); - return std::error_code(); } // Returns a buffer pointing to a member file containing a given symbol. // This function is thread-safe. -ErrorOr ArchiveFile::getMember(const Archive::Symbol *Sym) { +MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { auto ItOrErr = Sym->getMember(); - if (auto EC = ItOrErr.getError()) - return EC; + error(ItOrErr, + Twine("Could not get the member for symbol ") + Sym->getName()); Archive::child_iterator It = ItOrErr.get(); // Return an empty buffer if we have already returned the same buffer. if (Seen[It->getChildOffset()].test_and_set()) return MemoryBufferRef(); - return It->getMemoryBufferRef(); + ErrorOr Ret = It->getMemoryBufferRef(); + error(Ret, Twine("Could not get the buffer for the member defining symbol ") + + Sym->getName()); + return *Ret; } -std::error_code ObjectFile::parse() { +void ObjectFile::parse() { // Parse a memory buffer as a COFF file. auto BinOrErr = createBinary(MB); - if (auto EC = BinOrErr.getError()) - return EC; + error(BinOrErr, "Failed to parse object file"); std::unique_ptr Bin = std::move(BinOrErr.get()); if (auto *Obj = dyn_cast(Bin.get())) { Bin.release(); COFFObj.reset(Obj); } else { - llvm::errs() << getName() << " is not a COFF file.\n"; - return make_error_code(LLDError::InvalidFile); + error(Twine(getName()) + " is not a COFF file."); } // Read section and symbol tables. - if (auto EC = initializeChunks()) - return EC; - if (auto EC = initializeSymbols()) - return EC; - return initializeSEH(); + initializeChunks(); + initializeSymbols(); + initializeSEH(); } -std::error_code ObjectFile::initializeChunks() { +void ObjectFile::initializeChunks() { uint32_t NumSections = COFFObj->getNumberOfSections(); Chunks.reserve(NumSections); SparseChunks.resize(NumSections + 1); for (uint32_t I = 1; I < NumSections + 1; ++I) { const coff_section *Sec; StringRef Name; - 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); - } + std::error_code EC = COFFObj->getSection(I, Sec); + error(EC, Twine("getSection failed: ") + Name); + EC = COFFObj->getSectionName(Sec, Name); + error(EC, Twine("getSectionName failed: ") + Name); if (Name == ".sxdata") { SXData = Sec; continue; @@ -157,10 +148,9 @@ Chunks.push_back(C); SparseChunks[I] = C; } - return std::error_code(); } -std::error_code ObjectFile::initializeSymbols() { +void ObjectFile::initializeSymbols() { uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); SymbolBodies.reserve(NumSymbols); SparseSymbolBodies.resize(NumSymbols); @@ -168,11 +158,8 @@ for (uint32_t I = 0; I < NumSymbols; ++I) { // Get a COFFSymbolRef object. auto SymOrErr = COFFObj->getSymbol(I); - if (auto EC = SymOrErr.getError()) { - llvm::errs() << "broken object file: " << getName() << ": " - << EC.message() << "\n"; - return make_error_code(LLDError::BrokenFile); - } + error(SymOrErr, Twine("broken object file: ") + getName()); + COFFSymbolRef Sym = SymOrErr.get(); const void *AuxP = nullptr; @@ -195,7 +182,6 @@ I += Sym.getNumberOfAuxSymbols(); LastSectionNumber = Sym.getSectionNumber(); } - return std::error_code(); } Undefined *ObjectFile::createUndefined(COFFSymbolRef Sym) { @@ -258,20 +244,17 @@ return B; } -std::error_code ObjectFile::initializeSEH() { +void ObjectFile::initializeSEH() { if (!SEHCompat || !SXData) - return std::error_code(); + return; ArrayRef A; COFFObj->getSectionContents(SXData, A); - if (A.size() % 4 != 0) { - llvm::errs() << ".sxdata must be an array of symbol table indices\n"; - return make_error_code(LLDError::BrokenFile); - } + if (A.size() % 4 != 0) + error(".sxdata must be an array of symbol table indices"); auto *I = reinterpret_cast(A.data()); auto *E = reinterpret_cast(A.data() + A.size()); for (; I != E; ++I) SEHandlers.insert(SparseSymbolBodies[*I]); - return std::error_code(); } MachineTypes ObjectFile::getMachineType() { @@ -286,16 +269,14 @@ return S; } -std::error_code ImportFile::parse() { +void ImportFile::parse() { const char *Buf = MB.getBufferStart(); const char *End = MB.getBufferEnd(); const auto *Hdr = reinterpret_cast(Buf); // Check if the total size is valid. - if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData)) { - llvm::errs() << "broken import library\n"; - return make_error_code(LLDError::BrokenFile); - } + if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData)) + error("broken import library"); // Read names and create an __imp_ symbol. StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr))); @@ -327,18 +308,15 @@ auto *B = new (Alloc) DefinedImportThunk(Name, ImpSym, Hdr->Machine); SymbolBodies.push_back(B); } - return std::error_code(); } -std::error_code BitcodeFile::parse() { +void BitcodeFile::parse() { std::string Err; M.reset(LTOModule::createFromBuffer(MB.getBufferStart(), MB.getBufferSize(), llvm::TargetOptions(), Err)); - if (!Err.empty()) { - llvm::errs() << Err << '\n'; - return make_error_code(LLDError::BrokenFile); - } + if (!Err.empty()) + error(Err); llvm::BumpPtrStringSaver Saver(Alloc); for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) { @@ -362,7 +340,6 @@ } Directives = M->getLinkerOpts(); - return std::error_code(); } MachineTypes BitcodeFile::getMachineType() { Index: COFF/ModuleDef.cpp =================================================================== --- COFF/ModuleDef.cpp +++ COFF/ModuleDef.cpp @@ -111,12 +111,10 @@ public: explicit Parser(StringRef S, BumpPtrStringSaver *A) : Lex(S), Alloc(A) {} - std::error_code parse() { + void parse() { do { - if (auto EC = parseOne()) - return EC; + parseOne(); } while (Tok.K != Eof); - return std::error_code(); } private: @@ -129,80 +127,64 @@ Stack.pop_back(); } - std::error_code readAsInt(uint64_t *I) { + void readAsInt(uint64_t *I) { read(); - if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I)) { - llvm::errs() << "integer expected\n"; - return make_error_code(LLDError::InvalidOption); - } - return std::error_code(); + if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I)) + error("integer expected"); } - std::error_code expect(Kind Expected, StringRef Msg) { + void expect(Kind Expected, StringRef Msg) { read(); - if (Tok.K != Expected) { - llvm::errs() << Msg << "\n"; - return make_error_code(LLDError::InvalidOption); - } - return std::error_code(); + if (Tok.K != Expected) + error(Msg); } void unget() { Stack.push_back(Tok); } - std::error_code parseOne() { + void parseOne() { read(); switch (Tok.K) { case Eof: - return std::error_code(); + return; case KwExports: for (;;) { read(); if (Tok.K != Identifier) { unget(); - return std::error_code(); + return; } - if (auto EC = parseExport()) - return EC; + parseExport(); } case KwHeapsize: - if (auto EC = parseNumbers(&Config->HeapReserve, &Config->HeapCommit)) - return EC; - return std::error_code(); + parseNumbers(&Config->HeapReserve, &Config->HeapCommit); + return; case KwLibrary: - if (auto EC = parseName(&Config->OutputFile, &Config->ImageBase)) - return EC; + parseName(&Config->OutputFile, &Config->ImageBase); if (!StringRef(Config->OutputFile).endswith_lower(".dll")) Config->OutputFile += ".dll"; - return std::error_code(); + return; case KwStacksize: - if (auto EC = parseNumbers(&Config->StackReserve, &Config->StackCommit)) - return EC; - return std::error_code(); + parseNumbers(&Config->StackReserve, &Config->StackCommit); + return; case KwName: - if (auto EC = parseName(&Config->OutputFile, &Config->ImageBase)) - return EC; - return std::error_code(); + parseName(&Config->OutputFile, &Config->ImageBase); + return; case KwVersion: - if (auto EC = parseVersion(&Config->MajorImageVersion, - &Config->MinorImageVersion)) - return EC; - return std::error_code(); + parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion); + return; default: - llvm::errs() << "unknown directive: " << Tok.Value << "\n"; - return make_error_code(LLDError::InvalidOption); + error(Twine("unknown directive: ") + Tok.Value); } } - std::error_code parseExport() { + void parseExport() { Export E; E.Name = Tok.Value; read(); if (Tok.K == Equal) { read(); - if (Tok.K != Identifier) { - llvm::errs() << "identifier expected, but got " << Tok.Value << "\n"; - return make_error_code(LLDError::InvalidOption); - } + if (Tok.K != Identifier) + error(Twine("identifier expected, but got ") + Tok.Value); E.ExtName = E.Name; E.Name = Tok.Value; } else { @@ -234,68 +216,55 @@ } unget(); Config->Exports.push_back(E); - return std::error_code(); + return; } } // HEAPSIZE/STACKSIZE reserve[,commit] - std::error_code parseNumbers(uint64_t *Reserve, uint64_t *Commit) { - if (auto EC = readAsInt(Reserve)) - return EC; + void parseNumbers(uint64_t *Reserve, uint64_t *Commit) { + readAsInt(Reserve); read(); if (Tok.K != Comma) { unget(); Commit = 0; - return std::error_code(); + return; } - if (auto EC = readAsInt(Commit)) - return EC; - return std::error_code(); + readAsInt(Commit); } // NAME outputPath [BASE=address] - std::error_code parseName(std::string *Out, uint64_t *Baseaddr) { + void parseName(std::string *Out, uint64_t *Baseaddr) { read(); if (Tok.K == Identifier) { *Out = Tok.Value; } else { *Out = ""; unget(); - return std::error_code(); + return; } read(); if (Tok.K == KwBase) { - if (auto EC = expect(Equal, "'=' expected")) - return EC; - if (auto EC = readAsInt(Baseaddr)) - return EC; + expect(Equal, "'=' expected"); + readAsInt(Baseaddr); } else { unget(); *Baseaddr = 0; } - return std::error_code(); } // VERSION major[.minor] - std::error_code parseVersion(uint32_t *Major, uint32_t *Minor) { + void parseVersion(uint32_t *Major, uint32_t *Minor) { read(); - if (Tok.K != Identifier) { - llvm::errs() << "identifier expected, but got " << Tok.Value << "\n"; - return make_error_code(LLDError::InvalidOption); - } + if (Tok.K != Identifier) + error(Twine("identifier expected, but got ") + Tok.Value); StringRef V1, V2; std::tie(V1, V2) = Tok.Value.split('.'); - if (V1.getAsInteger(10, *Major)) { - llvm::errs() << "integer expected, but got " << Tok.Value << "\n"; - return make_error_code(LLDError::InvalidOption); - } - if (V2.empty()) { + if (V1.getAsInteger(10, *Major)) + error(Twine("integer expected, but got ") + Tok.Value); + if (V2.empty()) *Minor = 0; - } else if (V2.getAsInteger(10, *Minor)) { - llvm::errs() << "integer expected, but got " << Tok.Value << "\n"; - return make_error_code(LLDError::InvalidOption); - } - return std::error_code(); + else if (V2.getAsInteger(10, *Minor)) + error(Twine("integer expected, but got ") + Tok.Value); } Lexer Lex; @@ -306,8 +275,8 @@ } // anonymous namespace -std::error_code parseModuleDefs(MemoryBufferRef MB, BumpPtrStringSaver *Alloc) { - return Parser(MB.getBuffer(), Alloc).parse(); +void parseModuleDefs(MemoryBufferRef MB, BumpPtrStringSaver *Alloc) { + Parser(MB.getBuffer(), Alloc).parse(); } } // namespace coff Index: COFF/SymbolTable.h =================================================================== --- COFF/SymbolTable.h +++ COFF/SymbolTable.h @@ -43,13 +43,13 @@ public: void addFile(std::unique_ptr File); std::vector> &getFiles() { return Files; } - std::error_code step(); - std::error_code run(); + void step(); + void run(); bool queueEmpty(); // Print an error message on undefined symbols. If Resolve is true, try to // resolve any undefined symbols and update the symbol table accordingly. - bool reportRemainingUndefines(bool Resolve); + void reportRemainingUndefines(bool Resolve); // Returns a list of chunks of selected symbols. std::vector getChunks(); @@ -71,7 +71,7 @@ // Build a COFF object representing the combined contents of BitcodeFiles // and add it to the symbol table. Called after all files are added and // before the writer writes results to a file. - std::error_code addCombinedLTOObject(); + void addCombinedLTOObject(); // The writer needs to handle DLL import libraries specially in // order to create the import descriptor table. @@ -89,16 +89,16 @@ std::vector LocalImportChunks; private: - std::error_code readArchives(); - std::error_code readObjects(); + void readArchives(); + void readObjects(); - std::error_code addSymbol(SymbolBody *New); + void addSymbol(SymbolBody *New); void addLazy(Lazy *New, std::vector *Accum); Symbol *insert(SymbolBody *New); StringRef findByPrefix(StringRef Prefix); - std::error_code addMemberFile(Lazy *Body); - ErrorOr createLTOObject(llvm::LTOCodeGenerator *CG); + void addMemberFile(Lazy *Body); + ObjectFile *createLTOObject(llvm::LTOCodeGenerator *CG); llvm::DenseMap Symtab; Index: COFF/SymbolTable.cpp =================================================================== --- COFF/SymbolTable.cpp +++ COFF/SymbolTable.cpp @@ -40,26 +40,21 @@ } } -std::error_code SymbolTable::step() { +void SymbolTable::step() { if (queueEmpty()) - return std::error_code(); - if (auto EC = readObjects()) - return EC; - if (auto EC = readArchives()) - return EC; - return std::error_code(); + return; + readObjects(); + readArchives(); } -std::error_code SymbolTable::run() { +void SymbolTable::run() { while (!queueEmpty()) - if (auto EC = step()) - return EC; - return std::error_code(); + step(); } -std::error_code SymbolTable::readArchives() { +void SymbolTable::readArchives() { if (ArchiveQueue.empty()) - return std::error_code(); + return; // Add lazy symbols to the symbol table. Lazy symbols that conflict // with existing undefined symbols are accumulated in LazySyms. @@ -67,8 +62,7 @@ for (ArchiveFile *File : ArchiveQueue) { if (Config->Verbose) llvm::outs() << "Reading " << File->getShortName() << "\n"; - if (auto EC = File->parse()) - return EC; + File->parse(); for (Lazy *Sym : File->getLazySymbols()) addLazy(Sym, &LazySyms); } @@ -77,14 +71,12 @@ // Add archive member files to ObjectQueue that should resolve // existing undefined symbols. for (Symbol *Sym : LazySyms) - if (auto EC = addMemberFile(cast(Sym->Body))) - return EC; - return std::error_code(); + addMemberFile(cast(Sym->Body)); } -std::error_code SymbolTable::readObjects() { +void SymbolTable::readObjects() { if (ObjectQueue.empty()) - return std::error_code(); + return; // Add defined and undefined symbols to the symbol table. std::vector Directives; @@ -92,14 +84,12 @@ InputFile *File = ObjectQueue[I]; if (Config->Verbose) llvm::outs() << "Reading " << File->getShortName() << "\n"; - if (auto EC = File->parse()) - return EC; + File->parse(); // Adding symbols may add more files to ObjectQueue // (but not to ArchiveQueue). for (SymbolBody *Sym : File->getSymbols()) if (Sym->isExternal()) - if (auto EC = addSymbol(Sym)) - return EC; + addSymbol(Sym); StringRef S = File->getDirectives(); if (!S.empty()) { Directives.push_back(S); @@ -113,16 +103,14 @@ // Parse directive sections. This may add files to // ArchiveQueue and ObjectQueue. for (StringRef S : Directives) - if (auto EC = Driver->parseDirectives(S)) - return EC; - return std::error_code(); + Driver->parseDirectives(S); } bool SymbolTable::queueEmpty() { return ArchiveQueue.empty() && ObjectQueue.empty(); } -bool SymbolTable::reportRemainingUndefines(bool Resolve) { +void SymbolTable::reportRemainingUndefines(bool Resolve) { llvm::SmallPtrSet Undefs; for (auto &I : Symtab) { Symbol *Sym = I.second; @@ -157,7 +145,7 @@ Undefs.insert(Sym->Body); } if (Undefs.empty()) - return false; + return; for (Undefined *U : Config->GCRoot) if (Undefs.count(U->repl())) llvm::errs() << ": undefined symbol: " << U->getName() << "\n"; @@ -167,7 +155,8 @@ if (Undefs.count(Sym->repl())) llvm::errs() << File->getShortName() << ": undefined symbol: " << Sym->getName() << "\n"; - return !Config->Force; + if (!Config->Force) + error("Link failed"); } void SymbolTable::addLazy(Lazy *New, std::vector *Accum) { @@ -190,12 +179,12 @@ } } -std::error_code SymbolTable::addSymbol(SymbolBody *New) { +void SymbolTable::addSymbol(SymbolBody *New) { // Find an existing symbol or create and insert a new one. assert(isa(New) || isa(New)); Symbol *Sym = insert(New); if (Sym->Body == New) - return std::error_code(); + return; for (;;) { SymbolBody *Existing = Sym->Body; @@ -207,25 +196,25 @@ // since they would be replaced with weak aliases if they remain // undefined. if (auto *U = dyn_cast(New)) - if (!U->WeakAlias) - return addMemberFile(L); + if (!U->WeakAlias) { + addMemberFile(L); + return; + } if (!Sym->Body.compare_exchange_strong(Existing, New)) continue; - return std::error_code(); + return; } // compare() returns -1, 0, or 1 if the lhs symbol is less preferable, // equivalent (conflicting), or more preferable, respectively. int Comp = Existing->compare(New); - if (Comp == 0) { - llvm::errs() << "duplicate symbol: " << Existing->getDebugName() - << " and " << New->getDebugName() << "\n"; - return make_error_code(LLDError::DuplicateSymbols); - } + if (Comp == 0) + error(Twine("duplicate symbol: ") + Existing->getDebugName() + " and " + + New->getDebugName()); if (Comp < 0) if (!Sym->Body.compare_exchange_strong(Existing, New)) continue; - return std::error_code(); + return; } } @@ -241,21 +230,17 @@ } // Reads an archive member file pointed by a given symbol. -std::error_code SymbolTable::addMemberFile(Lazy *Body) { - auto FileOrErr = Body->getMember(); - if (auto EC = FileOrErr.getError()) - return EC; - std::unique_ptr File = std::move(FileOrErr.get()); +void SymbolTable::addMemberFile(Lazy *Body) { + std::unique_ptr File = Body->getMember(); // getMember returns an empty buffer if the member was already // read from the library. if (!File) - return std::error_code(); + return; if (Config->Verbose) llvm::outs() << "Loaded " << File->getShortName() << " for " << Body->getName() << "\n"; addFile(std::move(File)); - return std::error_code(); } std::vector SymbolTable::getChunks() { @@ -346,23 +331,19 @@ } } -std::error_code SymbolTable::addCombinedLTOObject() { +void SymbolTable::addCombinedLTOObject() { if (BitcodeFiles.empty()) - return std::error_code(); + return; // Diagnose any undefined symbols early, but do not resolve weak externals, // as resolution breaks the invariant that each Symbol points to a unique // SymbolBody, which we rely on to replace DefinedBitcode symbols correctly. - if (reportRemainingUndefines(/*Resolve=*/false)) - return make_error_code(LLDError::BrokenFile); + reportRemainingUndefines(/*Resolve=*/false); // Create an object file and add it to the symbol table by replacing any // DefinedBitcode symbols with the definitions in the object file. LTOCodeGenerator CG; - auto FileOrErr = createLTOObject(&CG); - if (auto EC = FileOrErr.getError()) - return EC; - ObjectFile *Obj = FileOrErr.get(); + ObjectFile *Obj = createLTOObject(&CG); for (SymbolBody *Body : Obj->getSymbols()) { if (!Body->isExternal()) @@ -379,34 +360,26 @@ if (auto *L = dyn_cast(Sym->Body)) { // We may see new references to runtime library symbols such as __chkstk // here. These symbols must be wholly defined in non-bitcode files. - if (auto EC = addMemberFile(L)) - return EC; + addMemberFile(L); continue; } SymbolBody *Existing = Sym->Body; int Comp = Existing->compare(Body); - if (Comp == 0) { - llvm::errs() << "LTO: unexpected duplicate symbol: " << Name << "\n"; - return make_error_code(LLDError::BrokenFile); - } + if (Comp == 0) + error(Twine("LTO: unexpected duplicate symbol: ") + Name); if (Comp < 0) Sym->Body = Body; } size_t NumBitcodeFiles = BitcodeFiles.size(); - if (auto EC = run()) - return EC; - if (BitcodeFiles.size() != NumBitcodeFiles) { - llvm::errs() << "LTO: late loaded symbol created new bitcode reference\n"; - return make_error_code(LLDError::BrokenFile); - } - - return std::error_code(); + run(); + if (BitcodeFiles.size() != NumBitcodeFiles) + error("LTO: late loaded symbol created new bitcode reference"); } // Combine and compile bitcode files and then return the result // as a regular COFF object file. -ErrorOr SymbolTable::createLTOObject(LTOCodeGenerator *CG) { +ObjectFile *SymbolTable::createLTOObject(LTOCodeGenerator *CG) { // All symbols referenced by non-bitcode objects must be preserved. for (ObjectFile *File : ObjectFiles) for (SymbolBody *Body : File->getSymbols()) @@ -433,15 +406,12 @@ std::string ErrMsg; LTOMB = CG->compile(false, false, false, ErrMsg); // take MB ownership - if (!LTOMB) { - llvm::errs() << ErrMsg << '\n'; - return make_error_code(LLDError::BrokenFile); - } + if (!LTOMB) + error(ErrMsg); auto *Obj = new ObjectFile(LTOMB->getMemBufferRef()); Files.emplace_back(Obj); ObjectFiles.push_back(Obj); - if (auto EC = Obj->parse()) - return EC; + Obj->parse(); return Obj; } Index: COFF/Symbols.h =================================================================== --- COFF/Symbols.h +++ COFF/Symbols.h @@ -270,7 +270,7 @@ // Returns an object file for this symbol, or a nullptr if the file // was already returned. - ErrorOr> getMember(); + std::unique_ptr getMember(); int getFileIndex() { return File->Index; } Index: COFF/Symbols.cpp =================================================================== --- COFF/Symbols.cpp +++ COFF/Symbols.cpp @@ -207,11 +207,8 @@ } } -ErrorOr> Lazy::getMember() { - auto MBRefOrErr = File->getMember(&Sym); - if (auto EC = MBRefOrErr.getError()) - return EC; - MemoryBufferRef MBRef = MBRefOrErr.get(); +std::unique_ptr Lazy::getMember() { + MemoryBufferRef MBRef = File->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. @@ -223,17 +220,15 @@ return std::unique_ptr(new ImportFile(MBRef)); std::unique_ptr Obj; - if (Magic == file_magic::coff_object) { + if (Magic == file_magic::coff_object) Obj.reset(new ObjectFile(MBRef)); - } else if (Magic == file_magic::bitcode) { + else if (Magic == file_magic::bitcode) Obj.reset(new BitcodeFile(MBRef)); - } else { - llvm::errs() << File->getName() << ": unknown file type\n"; - return make_error_code(LLDError::InvalidFile); - } + else + error(Twine(File->getName()) + ": unknown file type"); Obj->setParentName(File->getName()); - return std::move(Obj); + return Obj; } Defined *Undefined::getWeakAlias() { Index: COFF/Writer.h =================================================================== --- COFF/Writer.h +++ COFF/Writer.h @@ -18,7 +18,7 @@ class Chunk; class OutputSection; -std::error_code writeResult(SymbolTable *T); +void writeResult(SymbolTable *T); // Implemented in ICF.cpp. void doICF(const std::vector &Chunks); Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -9,6 +9,7 @@ #include "Config.h" #include "DLL.h" +#include "Error.h" #include "InputFiles.h" #include "SymbolTable.h" #include "Symbols.h" @@ -46,7 +47,7 @@ class Writer { public: Writer(SymbolTable *T) : Symtab(T) {} - std::error_code run(); + void run(); private: void markLive(); @@ -58,7 +59,7 @@ void assignAddresses(); void removeEmptySections(); void createSymbolAndStringTable(); - std::error_code openFile(StringRef OutputPath); + void openFile(StringRef OutputPath); template void writeHeader(); void fixSafeSEHSymbols(); void writeSections(); @@ -101,7 +102,7 @@ namespace lld { namespace coff { -std::error_code writeResult(SymbolTable *T) { return Writer(T).run(); } +void writeResult(SymbolTable *T) { Writer(T).run(); } // OutputSection represents a section in an output file. It's a // container of chunks. OutputSection and Chunk are 1:N relationship. @@ -198,13 +199,13 @@ uint64_t Defined::getSecrel() { if (auto *D = dyn_cast(this)) return getRVA() - D->getChunk()->getOutputSection()->getRVA(); - llvm::report_fatal_error("SECREL relocation points to a non-regular symbol"); + error("SECREL relocation points to a non-regular symbol"); } uint64_t Defined::getSectionIndex() { if (auto *D = dyn_cast(this)) return D->getChunk()->getOutputSection()->SectionIndex; - llvm::report_fatal_error("SECTION relocation points to a non-regular symbol"); + error("SECTION relocation points to a non-regular symbol"); } bool Defined::isExecutable() { @@ -218,7 +219,7 @@ } // namespace lld // The main function of the writer. -std::error_code Writer::run() { +void Writer::run() { markLive(); dedupCOMDATs(); createSections(); @@ -230,8 +231,7 @@ assignAddresses(); removeEmptySections(); createSymbolAndStringTable(); - if (auto EC = openFile(Config->OutputFile)) - return EC; + openFile(Config->OutputFile); if (Config->is64()) { writeHeader(); } else { @@ -240,7 +240,7 @@ fixSafeSEHSymbols(); writeSections(); sortExceptionTable(); - return Buffer->commit(); + error(Buffer->commit(), "Failed to write the output file"); } // Set live bit on for each reachable chunk. Unmarked (unreachable) @@ -692,13 +692,10 @@ memcpy(Buf + 4, Strtab.data(), Strtab.size()); } -std::error_code Writer::openFile(StringRef Path) { - if (auto EC = FileOutputBuffer::create(Path, FileSize, Buffer, - FileOutputBuffer::F_executable)) { - llvm::errs() << "failed to open " << Path << ": " << EC.message() << "\n"; - return EC; - } - return std::error_code(); +void Writer::openFile(StringRef Path) { + std::error_code EC = FileOutputBuffer::create(Path, FileSize, Buffer, + FileOutputBuffer::F_executable); + error(EC, Twine("failed to open ") + Path); } void Writer::fixSafeSEHSymbols() { Index: include/lld/Driver/Driver.h =================================================================== --- include/lld/Driver/Driver.h +++ include/lld/Driver/Driver.h @@ -143,7 +143,7 @@ /// Driver for Windows 'link.exe' command line options namespace coff { -bool link(llvm::ArrayRef args); +void link(llvm::ArrayRef args); } namespace elf2 { Index: lib/Driver/UniversalDriver.cpp =================================================================== --- lib/Driver/UniversalDriver.cpp +++ lib/Driver/UniversalDriver.cpp @@ -212,7 +212,8 @@ case Flavor::win_link: return WinLinkDriver::linkPECOFF(args, diagnostics); case Flavor::win_link2: - return coff::link(args); + coff::link(args); + return true; case Flavor::core: return CoreDriver::link(args, diagnostics); case Flavor::invalid: