Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -63,7 +63,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". @@ -126,9 +126,10 @@ 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) { @@ -138,8 +139,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)); }); if (Config->OutputFile == "") @@ -155,12 +157,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); @@ -238,7 +242,7 @@ case OPT_throwingnew: break; default: - fatal(Arg->getSpelling() + " is not allowed in .drectve"); + error(Arg->getSpelling() + " is not allowed in .drectve"); } } } @@ -456,6 +460,15 @@ // Parse command line options. opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1)); + // 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]); @@ -514,8 +527,9 @@ // Handle /noentry if (Args.hasArg(OPT_noentry)) { if (!Args.hasArg(OPT_dll)) - fatal("/noentry must be specified with /dll"); - Config->NoEntry = true; + error("/noentry must be specified with /dll"); + else + Config->NoEntry = true; } // Handle /dll @@ -526,10 +540,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 @@ -601,24 +617,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); } } @@ -686,6 +702,9 @@ if (Optional Path = findLib(Arg->getValue())) enqueuePath(*Path); + if (ErrorCount) + return; + // Windows specific -- Create a resource file containing a manifest file. if (Config->Manifest == Configuration::Embed) addBuffer(createManifestRes()); @@ -730,11 +749,13 @@ // 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()) - fatal("entry point must be defined"); - Config->Entry = addUndefined(S); - if (Config->Verbose) - outs() << "Entry name inferred: " << S << "\n"; + if (S.empty()) { + error("entry point must be defined"); + } else { + Config->Entry = addUndefined(S); + if (Config->Verbose) + outs() << "Entry name inferred: " << S << "\n"; + } } // Handle /export @@ -819,6 +840,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)) { @@ -844,10 +868,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 @@ -59,12 +59,13 @@ std::lock_guard Lock(Mu); if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) { + errs() << "error " << ErrorCount << " of " << Config->ErrorLimit << "\n"; print("error: ", raw_ostream::RED); *ErrorOS << Msg << "\n"; } 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 @@ -193,7 +193,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,33 @@ +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 +WRONG: could not open 01 +WRONG: could not open 19 +WRONG-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors) +WRONG-NOT: could not open 20