Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -59,7 +59,7 @@ (ErrorOS == &llvm::errs() && Process::StandardErrHasColors()); Driver = make(); Driver->link(Args); - return true; + return !ErrorCount; } // Drop directory components and replace extension with ".exe" or ".dll". @@ -121,10 +121,12 @@ return Symtab.addFile(make(MBRef)); if (Magic == file_magic::bitcode) return Symtab.addFile(make(MBRef)); + if (Magic == file_magic::coff_cl_gl_object) - fatal(MBRef.getBufferIdentifier() + ": is not a native COFF file. " + error(MBRef.getBufferIdentifier() + ": is not a native COFF file. " "Recompile without /GL"); - Symtab.addFile(make(MBRef)); + else + Symtab.addFile(make(MBRef)); } void LinkerDriver::enqueuePath(StringRef Path) { @@ -134,8 +136,9 @@ enqueueTask([=]() { auto MBOrErr = Future->get(); if (MBOrErr.second) - fatal(MBOrErr.second, "could not open " + PathStr); - Driver->addBuffer(std::move(MBOrErr.first)); + error("could not open " + PathStr + ": " + MBOrErr.second.message()); + else + Driver->addBuffer(std::move(MBOrErr.first)); }); } @@ -148,12 +151,14 @@ } InputFile *Obj; - if (Magic == file_magic::coff_object) + if (Magic == file_magic::coff_object) { Obj = make(MB); - else if (Magic == file_magic::bitcode) + } else if (Magic == file_magic::bitcode) { Obj = make(MB); - else - fatal("unknown file type: " + MB.getBufferIdentifier()); + } else { + error("unknown file type: " + MB.getBufferIdentifier()); + return; + } Obj->ParentName = ParentName; Symtab.addFile(Obj); @@ -230,7 +235,7 @@ case OPT_throwingnew: break; default: - fatal(Arg->getSpelling() + " is not allowed in .drectve"); + error(Arg->getSpelling() + " is not allowed in .drectve"); } } } @@ -581,6 +586,15 @@ V.push_back(Arg->getValue()); cl::ParseCommandLineOptions(V.size(), V.data()); + // Handle /errorlimit early, because error() depends on it. + if (auto *Arg = Args.getLastArg(OPT_errorlimit)) { + int N = 20; + StringRef S = Arg->getValue(); + if (S.getAsInteger(10, N)) + error(Arg->getSpelling() + " number expected, but got " + S); + Config->ErrorLimit = N; + } + // Handle /help if (Args.hasArg(OPT_help)) { printHelp(ArgsArr[0]); @@ -638,9 +652,10 @@ // Handle /noentry if (Args.hasArg(OPT_noentry)) { - if (!Args.hasArg(OPT_dll)) - fatal("/noentry must be specified with /dll"); - Config->NoEntry = true; + if (Args.hasArg(OPT_dll)) + Config->NoEntry = true; + else + error("/noentry must be specified with /dll"); } // Handle /dll @@ -651,10 +666,12 @@ // Handle /fixed if (Args.hasArg(OPT_fixed)) { - if (Args.hasArg(OPT_dynamicbase)) - fatal("/fixed must not be specified with /dynamicbase"); - Config->Relocatable = false; - Config->DynamicBase = false; + if (Args.hasArg(OPT_dynamicbase)) { + error("/fixed must not be specified with /dynamicbase"); + } else { + Config->Relocatable = false; + Config->DynamicBase = false; + } } // Handle /machine @@ -726,24 +743,24 @@ StringRef OptLevel = StringRef(S).substr(7); if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || Config->LTOOptLevel > 3) - fatal("/opt:lldlto: invalid optimization level: " + OptLevel); + error("/opt:lldlto: invalid optimization level: " + OptLevel); continue; } if (StringRef(S).startswith("lldltojobs=")) { StringRef Jobs = StringRef(S).substr(11); if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0) - fatal("/opt:lldltojobs: invalid job count: " + Jobs); + error("/opt:lldltojobs: invalid job count: " + Jobs); continue; } if (StringRef(S).startswith("lldltopartitions=")) { StringRef N = StringRef(S).substr(17); if (N.getAsInteger(10, Config->LTOPartitions) || Config->LTOPartitions == 0) - fatal("/opt:lldltopartitions: invalid partition count: " + N); + error("/opt:lldltopartitions: invalid partition count: " + N); continue; } if (S != "ref" && S != "lbr" && S != "nolbr") - fatal("/opt: unknown option: " + S); + error("/opt: unknown option: " + S); } } @@ -801,6 +818,9 @@ Config->MapFile = getMapFile(Args); + if (ErrorCount) + return; + // Create a list of input files. Files can be given as arguments // for /defaultlib option. std::vector MBs; @@ -959,6 +979,9 @@ addUndefined(mangle("_load_config_used")); } while (run()); + if (ErrorCount) + return; + // If /msvclto is given, we use the MSVC linker to link LTO output files. // This is useful because MSVC link.exe can generate complete PDBs. if (Args.hasArg(OPT_msvclto)) { @@ -983,10 +1006,13 @@ } // Handle /safeseh. - if (Args.hasArg(OPT_safeseh)) + if (Args.hasArg(OPT_safeseh)) { for (ObjectFile *File : Symtab.ObjectFiles) if (!File->SEHCompat) - fatal("/safeseh: " + File->getName() + " is not compatible with SEH"); + error("/safeseh: " + File->getName() + " is not compatible with SEH"); + if (ErrorCount) + return; + } // Windows specific -- when we are creating a .dll file, we also // need to create a .lib file. Index: lld/trunk/COFF/Error.cpp =================================================================== --- lld/trunk/COFF/Error.cpp +++ lld/trunk/COFF/Error.cpp @@ -77,7 +77,7 @@ } else if (ErrorCount == Config->ErrorLimit) { print("error: ", raw_ostream::RED); *ErrorOS << "too many errors emitted, stopping now" - << " (use -error-limit=0 to see all errors)\n"; + << " (use /ERRORLIMIT:0 to see all errors)\n"; exitLld(1); } Index: lld/trunk/COFF/Options.td =================================================================== --- lld/trunk/COFF/Options.td +++ lld/trunk/COFF/Options.td @@ -21,6 +21,8 @@ def defaultlib : P<"defaultlib", "Add the library to the list of input files">; def delayload : P<"delayload", "Delay loaded DLL name">; def entry : P<"entry", "Name of entry point symbol">; +def errorlimit : P<"errorlimit", + "Maximum number of errors to emit before stopping (0 = no limit)">; def export : P<"export", "Export a function">; // No help text because /failifmismatch is not intended to be used by the user. def failifmismatch : P<"failifmismatch", "">; Index: lld/trunk/COFF/SymbolTable.cpp =================================================================== --- lld/trunk/COFF/SymbolTable.cpp +++ lld/trunk/COFF/SymbolTable.cpp @@ -190,7 +190,7 @@ } void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { - fatal("duplicate symbol: " + toString(*Existing->body()) + " in " + + error("duplicate symbol: " + toString(*Existing->body()) + " in " + toString(Existing->body()->getFile()) + " and in " + (NewFile ? toString(NewFile) : "(internal)")); } Index: lld/trunk/test/COFF/error-limit.test =================================================================== --- lld/trunk/test/COFF/error-limit.test +++ lld/trunk/test/COFF/error-limit.test @@ -0,0 +1,29 @@ +RUN: not lld-link 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 \ +RUN: 21 22 2>&1 | FileCheck -check-prefix=DEFAULT %s + +DEFAULT: could not open 01 +DEFAULT: could not open 20 +DEFAULT-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors) +DEFAULT-NOT: could not open 21 + +RUN: not lld-link /ERRORLIMIT:5 01 02 03 04 05 06 07 08 09 10 2>&1 \ +RUN: | FileCheck -check-prefix=LIMIT5 %s + +LIMIT5: could not open 01 +LIMIT5: could not open 05 +LIMIT5-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors) +LIMIT5-NOT: could not open 06 + +RUN: not lld-link /ERRORLIMIT:0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \ +RUN: 16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=UNLIMITED %s + +UNLIMITED: could not open 01 +UNLIMITED: could not open 20 +UNLIMITED: could not open 21 +UNLIMITED: could not open 22 +UNLIMITED-NOT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors) + +RUN: not lld-link /ERRORLIMIT:XYZ 01 02 03 04 05 06 07 08 09 10 11 12 13 14 \ +RUN: 15 16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=WRONG %s + +WRONG: /ERRORLIMIT: number expected, but got XYZ