From 21eecb4f14cd36a7c5beb40437fd70b5a966922d Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Tue, 2 Feb 2016 21:13:09 +0000 Subject: [PATCH] Re-submit ELF: Report multiple errors from the driver. This reverts r259395 which reverted r259143. llvm-svn: 259572 --- lld/ELF/Driver.cpp | 38 +++++++++++++++++++++++----------- lld/ELF/Driver.h | 1 + lld/ELF/DriverUtils.cpp | 7 +++---- lld/ELF/Error.cpp | 16 ++++++++------ lld/ELF/Error.h | 14 ++++++++----- lld/ELF/LinkerScript.cpp | 2 +- lld/test/ELF/driver.test | 9 ++++++++ lld/test/ELF/invalid-linkerscript.test | 38 +++++++++++++++++----------------- 8 files changed, 78 insertions(+), 47 deletions(-) create mode 100644 lld/test/ELF/driver.test diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 677d40b..8340206 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -55,8 +55,10 @@ static std::pair parseEmulation(StringRef S) { if (S == "aarch64linux") return {ELF64LEKind, EM_AARCH64}; if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") - fatal("Windows targets are not supported on the ELF frontend: " + S); - fatal("Unknown emulation: " + S); + error("Windows targets are not supported on the ELF frontend: " + S); + else + error("Unknown emulation: " + S); + return {ELFNoneKind, 0}; } // Returns slices of MB by parsing MB as an archive file. @@ -84,7 +86,8 @@ void LinkerDriver::addFile(StringRef Path) { if (Config->Verbose) llvm::outs() << Path << "\n"; auto MBOrErr = MemoryBuffer::getFile(Path); - fatal(MBOrErr, "cannot open " + Path); + if (error(MBOrErr, "cannot open " + Path)) + return; std::unique_ptr &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); OwningMBs.push_back(std::move(MB)); // take MB ownership @@ -110,6 +113,15 @@ void LinkerDriver::addFile(StringRef Path) { } } +// Add a given library by searching it from input search paths. +void LinkerDriver::addLibrary(StringRef Name) { + std::string Path = searchLibrary(Name); + if (Path.empty()) + error("Unable to find library -l" + Name); + else + addFile(Path); +} + // Some command line options or some combinations of them are not allowed. // This function checks for such errors. static void checkOptions(opt::InputArgList &Args) { @@ -117,15 +129,15 @@ static void checkOptions(opt::InputArgList &Args) { // of executables or DSOs. We don't support that since the feature // does not seem to provide more value than the static archiver. if (Args.hasArg(OPT_relocatable)) - fatal("-r option is not supported. Use 'ar' command instead."); + error("-r option is not supported. Use 'ar' command instead."); // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup // table which is a relatively new feature. if (Config->EMachine == EM_MIPS && Config->GnuHash) - fatal("The .gnu.hash section is not compatible with the MIPS target."); + error("The .gnu.hash section is not compatible with the MIPS target."); if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty()) - fatal("-e option is not valid for AMDGPU."); + error("-e option is not valid for AMDGPU."); } static StringRef @@ -149,6 +161,8 @@ void LinkerDriver::main(ArrayRef ArgsArr) { readConfigs(Args); createFiles(Args); checkOptions(Args); + if (HasError) + return; switch (Config->EKind) { case ELF32LEKind: @@ -164,7 +178,7 @@ void LinkerDriver::main(ArrayRef ArgsArr) { link(Args); return; default: - fatal("-m or at least a .o file required"); + error("-m or at least a .o file required"); } } @@ -221,7 +235,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_O)) { StringRef Val = Arg->getValue(); if (Val.getAsInteger(10, Config->Optimize)) - fatal("Invalid optimization level"); + error("Invalid optimization level"); } if (auto *Arg = Args.getLastArg(OPT_hash_style)) { @@ -232,7 +246,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { } else if (S == "both") { Config->GnuHash = true; } else if (S != "sysv") - fatal("Unknown hash style: " + S); + error("Unknown hash style: " + S); } for (auto *Arg : Args.filtered(OPT_undefined)) @@ -243,7 +257,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_l: - addFile(searchLibrary(Arg->getValue())); + addLibrary(Arg->getValue()); break; case OPT_INPUT: case OPT_script: @@ -270,8 +284,8 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { } } - if (Files.empty()) - fatal("no input files."); + if (Files.empty() && !HasError) + error("no input files."); } template void LinkerDriver::link(opt::InputArgList &Args) { diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h index 95b6d96..adcf457 100644 --- a/lld/ELF/Driver.h +++ b/lld/ELF/Driver.h @@ -27,6 +27,7 @@ class LinkerDriver { public: void main(ArrayRef Args); void addFile(StringRef Path); + void addLibrary(StringRef Name); private: void readConfigs(llvm::opt::InputArgList &Args); diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp index 52e4633..bbe5f9f 100644 --- a/lld/ELF/DriverUtils.cpp +++ b/lld/ELF/DriverUtils.cpp @@ -66,7 +66,7 @@ opt::InputArgList elf2::parseArgs(llvm::BumpPtrAllocator *A, // Parse options and then do error checking. opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); if (MissingCount) - fatal(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + + error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + "\", expected " + Twine(MissingCount) + (MissingCount == 1 ? " argument.\n" : " arguments")); @@ -74,8 +74,7 @@ opt::InputArgList elf2::parseArgs(llvm::BumpPtrAllocator *A, for (auto *Arg : Unknowns) warning("warning: unknown argument: " + Arg->getSpelling()); if (Unknowns.begin() != Unknowns.end()) - fatal("unknown argument(s) found"); - + error("unknown argument(s) found"); return Args; } @@ -104,7 +103,7 @@ std::string elf2::searchLibrary(StringRef Path) { if (!S.empty()) return S; } - fatal("Unable to find library -l" + Path); + return ""; } // Makes a path by concatenating Dir and File. diff --git a/lld/ELF/Error.cpp b/lld/ELF/Error.cpp index 327bb26..e3add1b 100644 --- a/lld/ELF/Error.cpp +++ b/lld/ELF/Error.cpp @@ -24,14 +24,18 @@ void error(const Twine &Msg) { HasError = true; } -void error(std::error_code EC, const Twine &Prefix) { - if (EC) - error(Prefix + ": " + EC.message()); +bool error(std::error_code EC, const Twine &Prefix) { + if (!EC) + return false; + error(Prefix + ": " + EC.message()); + return true; } -void error(std::error_code EC) { - if (EC) - error(EC.message()); +bool error(std::error_code EC) { + if (!EC) + return false; + error(EC.message()); + return true; } void fatal(const Twine &Msg) { diff --git a/lld/ELF/Error.h b/lld/ELF/Error.h index 3b6aa69..546e1d3 100644 --- a/lld/ELF/Error.h +++ b/lld/ELF/Error.h @@ -20,13 +20,16 @@ extern bool HasError; void warning(const Twine &Msg); void error(const Twine &Msg); -void error(std::error_code EC, const Twine &Prefix); -void error(std::error_code EC); +bool error(std::error_code EC, const Twine &Prefix); +bool error(std::error_code EC); -template void error(const ErrorOr &V, const Twine &Prefix) { - error(V.getError(), Prefix); +template bool error(const ErrorOr &V, const Twine &Prefix) { + return error(V.getError(), Prefix); +} + +template bool error(const ErrorOr &V) { + return error(V.getError()); } -template void error(const ErrorOr &V) { error(V.getError()); } LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); void fatal(std::error_code EC, const Twine &Prefix); @@ -35,6 +38,7 @@ void fatal(std::error_code EC); template void fatal(const ErrorOr &V, const Twine &Prefix) { fatal(V.getError(), Prefix); } + template void fatal(const ErrorOr &V) { fatal(V.getError()); } } // namespace elf2 diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 8980441..7e0ed34 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -206,7 +206,7 @@ void LinkerScript::addFile(StringRef S) { else Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1))); } else if (S.startswith("-l")) { - Driver->addFile(searchLibrary(S.substr(2))); + Driver->addLibrary(S.substr(2)); } else if (sys::fs::exists(S)) { Driver->addFile(S); } else { diff --git a/lld/test/ELF/driver.test b/lld/test/ELF/driver.test new file mode 100644 index 0000000..13f040e --- /dev/null +++ b/lld/test/ELF/driver.test @@ -0,0 +1,9 @@ +# RUN: not ld.lld -unknown1 -unknown2 -m foo /no/such/file -lnosuchlib \ +# RUN: 2>&1 | FileCheck %s + +# CHECK: warning: unknown argument: -unknown1 +# CHECK: warning: unknown argument: -unknown2 +# CHECK: unknown argument(s) found +# CHECK: Unknown emulation: foo +# CHECK: cannot open /no/such/file +# CHECK: Unable to find library -lnosuchlib diff --git a/lld/test/ELF/invalid-linkerscript.test b/lld/test/ELF/invalid-linkerscript.test index 3dea83d..a69cd3f 100644 --- a/lld/test/ELF/invalid-linkerscript.test +++ b/lld/test/ELF/invalid-linkerscript.test @@ -1,45 +1,45 @@ # RUN: mkdir -p %t.dir -## Note that we will see "no input files" error message after -## error messages from the linker script parser, because the -## linker keeps going when an error is found. +## Note that we are using "-r option is not supported" as a marker +## that the linker keep going when it found an error. That specific +## error message is not related to the linker script tests. # RUN: echo foobar > %t1 -# RUN: not ld.lld %t1 2>&1 | FileCheck -check-prefix=ERR1 %s +# RUN: not ld.lld -r %t1 2>&1 | FileCheck -check-prefix=ERR1 %s # ERR1: unknown directive: foobar -# ERR1: no input files +# ERR1: -r option is not supported # RUN: echo "foo \"bar" > %t2 -# RUN: not ld.lld %t2 2>&1 | FileCheck -check-prefix=ERR2 %s +# RUN: not ld.lld -r %t2 2>&1 | FileCheck -check-prefix=ERR2 %s # ERR2: unclosed quote -# ERR2: no input files +# ERR2: -r option is not supported # RUN: echo "/*" > %t3 -# RUN: not ld.lld %t3 2>&1 | FileCheck -check-prefix=ERR3 %s +# RUN: not ld.lld -r %t3 2>&1 | FileCheck -check-prefix=ERR3 %s # ERR3: unclosed comment -# ERR3: no input files +# ERR3: -r option is not supported # RUN: echo "EXTERN (" > %t4 -# RUN: not ld.lld %t4 2>&1 | FileCheck -check-prefix=ERR4 %s +# RUN: not ld.lld -r %t4 2>&1 | FileCheck -check-prefix=ERR4 %s # ERR4: unexpected EOF -# ERR4: no input files +# ERR4: -r option is not supported # RUN: echo "EXTERN (" > %t5 -# RUN: not ld.lld %t5 2>&1 | FileCheck -check-prefix=ERR5 %s +# RUN: not ld.lld -r %t5 2>&1 | FileCheck -check-prefix=ERR5 %s # ERR5: unexpected EOF -# ERR5: no input files +# ERR5: -r option is not supported # RUN: echo "EXTERN xyz" > %t6 -# RUN: not ld.lld %t6 2>&1 | FileCheck -check-prefix=ERR6 %s +# RUN: not ld.lld -r %t6 2>&1 | FileCheck -check-prefix=ERR6 %s # ERR6: ( expected, but got xyz -# ERR6: no input files +# ERR6: -r option is not supported # RUN: echo "INCLUDE /no/such/file" > %t7 -# RUN: not ld.lld %t7 2>&1 | FileCheck -check-prefix=ERR7 %s +# RUN: not ld.lld -r %t7 2>&1 | FileCheck -check-prefix=ERR7 %s # ERR7: cannot open /no/such/file -# ERR7: no input files +# ERR7: -r option is not supported # RUN: echo "OUTPUT_FORMAT(x y z)" > %t8 -# RUN: not ld.lld %t8 2>&1 | FileCheck -check-prefix=ERR8 %s +# RUN: not ld.lld -r %t8 2>&1 | FileCheck -check-prefix=ERR8 %s # ERR8: unexpected token: y -# ERR8: no input files +# ERR8: -r option is not supported \ No newline at end of file -- 2.7.4