[lld-link] Replace error(...) with Err

This commit is contained in:
Fangrui Song 2024-12-05 19:44:26 -08:00
parent f0b09dfd4c
commit 8d225f10ef
7 changed files with 104 additions and 92 deletions

View File

@ -49,7 +49,7 @@ struct Cluster {
class CallGraphSort { class CallGraphSort {
public: public:
CallGraphSort(const COFFLinkerContext &ctx); CallGraphSort(COFFLinkerContext &ctx);
DenseMap<const SectionChunk *, int> run(); DenseMap<const SectionChunk *, int> run();
@ -57,7 +57,7 @@ private:
std::vector<Cluster> clusters; std::vector<Cluster> clusters;
std::vector<const SectionChunk *> sections; std::vector<const SectionChunk *> sections;
const COFFLinkerContext &ctx; COFFLinkerContext &ctx;
}; };
// Maximum amount the combined cluster density can be worse than the original // Maximum amount the combined cluster density can be worse than the original
@ -73,7 +73,7 @@ using SectionPair = std::pair<const SectionChunk *, const SectionChunk *>;
// Take the edge list in Config->CallGraphProfile, resolve symbol names to // Take the edge list in Config->CallGraphProfile, resolve symbol names to
// Symbols, and generate a graph between InputSections with the provided // Symbols, and generate a graph between InputSections with the provided
// weights. // weights.
CallGraphSort::CallGraphSort(const COFFLinkerContext &ctx) : ctx(ctx) { CallGraphSort::CallGraphSort(COFFLinkerContext &ctx) : ctx(ctx) {
const MapVector<SectionPair, uint64_t> &profile = ctx.config.callGraphProfile; const MapVector<SectionPair, uint64_t> &profile = ctx.config.callGraphProfile;
DenseMap<const SectionChunk *, int> secToCluster; DenseMap<const SectionChunk *, int> secToCluster;
@ -211,7 +211,8 @@ DenseMap<const SectionChunk *, int> CallGraphSort::run() {
std::error_code ec; std::error_code ec;
raw_fd_ostream os(ctx.config.printSymbolOrder, ec, sys::fs::OF_None); raw_fd_ostream os(ctx.config.printSymbolOrder, ec, sys::fs::OF_None);
if (ec) { if (ec) {
error("cannot open " + ctx.config.printSymbolOrder + ": " + ec.message()); Err(ctx) << "cannot open " << ctx.config.printSymbolOrder << ": "
<< ec.message();
return orderMap; return orderMap;
} }
// Print the symbols ordered by C3, in the order of increasing curOrder // Print the symbols ordered by C3, in the order of increasing curOrder
@ -244,6 +245,6 @@ DenseMap<const SectionChunk *, int> CallGraphSort::run() {
// according to the C³ heuristic. All clusters are then sorted by a density // according to the C³ heuristic. All clusters are then sorted by a density
// metric to further improve locality. // metric to further improve locality.
DenseMap<const SectionChunk *, int> DenseMap<const SectionChunk *, int>
coff::computeCallGraphProfileOrder(const COFFLinkerContext &ctx) { coff::computeCallGraphProfileOrder(COFFLinkerContext &ctx) {
return CallGraphSort(ctx).run(); return CallGraphSort(ctx).run();
} }

View File

@ -16,7 +16,7 @@ class SectionChunk;
class COFFLinkerContext; class COFFLinkerContext;
llvm::DenseMap<const SectionChunk *, int> llvm::DenseMap<const SectionChunk *, int>
computeCallGraphProfileOrder(const COFFLinkerContext &ctx); computeCallGraphProfileOrder(COFFLinkerContext &ctx);
} // namespace lld::coff } // namespace lld::coff
#endif #endif

View File

@ -101,8 +101,8 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
} }
// Parse options of the form "old;new". // Parse options of the form "old;new".
static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args, static std::pair<StringRef, StringRef>
unsigned id) { getOldNewOptions(COFFLinkerContext &ctx, opt::InputArgList &args, unsigned id) {
auto *arg = args.getLastArg(id); auto *arg = args.getLastArg(id);
if (!arg) if (!arg)
return {"", ""}; return {"", ""};
@ -110,14 +110,16 @@ static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args,
StringRef s = arg->getValue(); StringRef s = arg->getValue();
std::pair<StringRef, StringRef> ret = s.split(';'); std::pair<StringRef, StringRef> ret = s.split(';');
if (ret.second.empty()) if (ret.second.empty())
error(arg->getSpelling() + " expects 'old;new' format, but got " + s); Err(ctx) << arg->getSpelling() << " expects 'old;new' format, but got "
<< s;
return ret; return ret;
} }
// Parse options of the form "old;new[;extra]". // Parse options of the form "old;new[;extra]".
static std::tuple<StringRef, StringRef, StringRef> static std::tuple<StringRef, StringRef, StringRef>
getOldNewOptionsExtra(opt::InputArgList &args, unsigned id) { getOldNewOptionsExtra(COFFLinkerContext &ctx, opt::InputArgList &args,
auto [oldDir, second] = getOldNewOptions(args, id); unsigned id) {
auto [oldDir, second] = getOldNewOptions(ctx, args, id);
auto [newDir, extraDir] = second.split(';'); auto [newDir, extraDir] = second.split(';');
return {oldDir, newDir, extraDir}; return {oldDir, newDir, extraDir};
} }
@ -243,13 +245,14 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
break; break;
} }
if (filename.ends_with_insensitive(".dll")) { if (filename.ends_with_insensitive(".dll")) {
error(filename + ": bad file type. Did you specify a DLL instead of an " Err(ctx) << filename
"import library?"); << ": bad file type. Did you specify a DLL instead of an "
"import library?";
break; break;
} }
[[fallthrough]]; [[fallthrough]];
default: default:
error(mbref.getBufferIdentifier() + ": unknown file type"); Err(ctx) << mbref.getBufferIdentifier() << ": unknown file type";
break; break;
} }
} }
@ -289,9 +292,9 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
// directory. // directory.
std::string nearest; std::string nearest;
if (ctx.optTable.findNearest(pathStr, nearest) > 1) if (ctx.optTable.findNearest(pathStr, nearest) > 1)
error(msg); Err(ctx) << msg;
else else
error(msg + "; did you mean '" + nearest + "'"); Err(ctx) << msg << "; did you mean '" << nearest << "'";
} else } else
ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy); ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy);
}); });
@ -315,11 +318,11 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName,
obj = obj =
make<BitcodeFile>(ctx, mb, parentName, offsetInArchive, /*lazy=*/false); make<BitcodeFile>(ctx, mb, parentName, offsetInArchive, /*lazy=*/false);
} else if (magic == file_magic::coff_cl_gl_object) { } else if (magic == file_magic::coff_cl_gl_object) {
error(mb.getBufferIdentifier() + Err(ctx) << mb.getBufferIdentifier()
": is not a native COFF file. Recompile without /GL?"); << ": is not a native COFF file. Recompile without /GL?";
return; return;
} else { } else {
error("unknown file type: " + mb.getBufferIdentifier()); Err(ctx) << "unknown file type: " << mb.getBufferIdentifier();
return; return;
} }
@ -485,8 +488,8 @@ void LinkerDriver::parseDirectives(InputFile *file) {
case OPT_inferasanlibs_no: case OPT_inferasanlibs_no:
break; break;
default: default:
error(arg->getSpelling() + " is not allowed in .drectve (" + Err(ctx) << arg->getSpelling() << " is not allowed in .drectve ("
toString(file) + ")"); << toString(file) << ")";
} }
} }
} }
@ -751,7 +754,7 @@ Symbol *LinkerDriver::addUndefined(StringRef name, bool aliasEC) {
void LinkerDriver::addUndefinedGlob(StringRef arg) { void LinkerDriver::addUndefinedGlob(StringRef arg) {
Expected<GlobPattern> pat = GlobPattern::create(arg); Expected<GlobPattern> pat = GlobPattern::create(arg);
if (!pat) { if (!pat) {
error("/includeglob: " + toString(pat.takeError())); Err(ctx) << "/includeglob: " << toString(pat.takeError());
return; return;
} }
@ -1133,7 +1136,7 @@ void LinkerDriver::parseOrderFile(StringRef arg) {
// For some reason, the MSVC linker requires a filename to be // For some reason, the MSVC linker requires a filename to be
// preceded by "@". // preceded by "@".
if (!arg.starts_with("@")) { if (!arg.starts_with("@")) {
error("malformed /order option: '@' missing"); Err(ctx) << "malformed /order option: '@' missing";
return; return;
} }
@ -1206,7 +1209,7 @@ void LinkerDriver::parseCallGraphFile(StringRef path) {
uint64_t count; uint64_t count;
if (fields.size() != 3 || !to_integer(fields[2], count)) { if (fields.size() != 3 || !to_integer(fields[2], count)) {
error(path + ": parse error"); Err(ctx) << path << ": parse error";
return; return;
} }
@ -1360,10 +1363,11 @@ void LinkerDriver::convertResources() {
if (!ctx.config.mingw && if (!ctx.config.mingw &&
(resourceObjFiles.size() > 1 || (resourceObjFiles.size() > 1 ||
(resourceObjFiles.size() == 1 && !resources.empty()))) { (resourceObjFiles.size() == 1 && !resources.empty()))) {
error((!resources.empty() ? "internal .obj file created from .res files" Err(ctx) << (!resources.empty()
: toString(resourceObjFiles[1])) + ? "internal .obj file created from .res files"
": more than one resource obj file not allowed, already got " + : toString(resourceObjFiles[1]))
toString(resourceObjFiles.front())); << ": more than one resource obj file not allowed, already got "
<< resourceObjFiles.front();
return; return;
} }
@ -1528,7 +1532,7 @@ std::optional<std::string> getReproduceFile(const opt::InputArgList &args) {
} }
static std::unique_ptr<llvm::vfs::FileSystem> static std::unique_ptr<llvm::vfs::FileSystem>
getVFS(const opt::InputArgList &args) { getVFS(COFFLinkerContext &ctx, const opt::InputArgList &args) {
using namespace llvm::vfs; using namespace llvm::vfs;
const opt::Arg *arg = args.getLastArg(OPT_vfsoverlay); const opt::Arg *arg = args.getLastArg(OPT_vfsoverlay);
@ -1545,7 +1549,7 @@ getVFS(const opt::InputArgList &args) {
/*DiagHandler*/ nullptr, arg->getValue())) /*DiagHandler*/ nullptr, arg->getValue()))
return ret; return ret;
error("Invalid vfs overlay"); Err(ctx) << "Invalid vfs overlay";
return nullptr; return nullptr;
} }
@ -1606,11 +1610,11 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
int n = 20; int n = 20;
StringRef s = arg->getValue(); StringRef s = arg->getValue();
if (s.getAsInteger(10, n)) if (s.getAsInteger(10, n))
error(arg->getSpelling() + " number expected, but got " + s); Err(ctx) << arg->getSpelling() << " number expected, but got " << s;
ctx.e.errorLimit = n; ctx.e.errorLimit = n;
} }
config->vfs = getVFS(args); config->vfs = getVFS(ctx, args);
// Handle /help // Handle /help
if (args.hasArg(OPT_help)) { if (args.hasArg(OPT_help)) {
@ -1624,8 +1628,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
StringRef v(arg->getValue()); StringRef v(arg->getValue());
unsigned threads = 0; unsigned threads = 0;
if (!llvm::to_integer(v, threads, 0) || threads == 0) if (!llvm::to_integer(v, threads, 0) || threads == 0)
error(arg->getSpelling() + ": expected a positive integer, but got '" + Err(ctx) << arg->getSpelling()
arg->getValue() + "'"); << ": expected a positive integer, but got '" << arg->getValue()
<< "'";
parallel::strategy = hardware_concurrency(threads); parallel::strategy = hardware_concurrency(threads);
config->thinLTOJobs = v.str(); config->thinLTOJobs = v.str();
} }
@ -1661,8 +1666,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (errOrWriter) { if (errOrWriter) {
tar = std::move(*errOrWriter); tar = std::move(*errOrWriter);
} else { } else {
error("/linkrepro: failed to open " + *path + ": " + Err(ctx) << "/linkrepro: failed to open " << *path << ": "
toString(errOrWriter.takeError())); << toString(errOrWriter.takeError());
} }
} }
} }
@ -1788,7 +1793,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
} else if (s == "nosymtab") { } else if (s == "nosymtab") {
config->writeSymtab = false; config->writeSymtab = false;
} else { } else {
error("/debug: unknown option: " + s); Err(ctx) << "/debug: unknown option: " << s;
} }
} }
} }
@ -1841,7 +1846,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (args.hasArg(OPT_dll)) if (args.hasArg(OPT_dll))
config->noEntry = true; config->noEntry = true;
else else
error("/noentry must be specified with /dll"); Err(ctx) << "/noentry must be specified with /dll";
} }
// Handle /dll // Handle /dll
@ -1865,7 +1870,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (fixed) { if (fixed) {
if (dynamicBaseArg && if (dynamicBaseArg &&
dynamicBaseArg->getOption().getID() == OPT_dynamicbase) { dynamicBaseArg->getOption().getID() == OPT_dynamicbase) {
error("/fixed must not be specified with /dynamicbase"); Err(ctx) << "/fixed must not be specified with /dynamicbase";
} else { } else {
config->relocatable = false; config->relocatable = false;
config->dynamicBase = false; config->dynamicBase = false;
@ -1906,7 +1911,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (auto *arg = args.getLastArg(OPT_filealign)) { if (auto *arg = args.getLastArg(OPT_filealign)) {
parseNumbers(arg->getValue(), &config->fileAlign); parseNumbers(arg->getValue(), &config->fileAlign);
if (!isPowerOf2_64(config->fileAlign)) if (!isPowerOf2_64(config->fileAlign))
error("/filealign: not a power of two: " + Twine(config->fileAlign)); Err(ctx) << "/filealign: not a power of two: " << config->fileAlign;
} }
// Handle /stack // Handle /stack
@ -2013,21 +2018,22 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
ltoDebugPM = false; ltoDebugPM = false;
} else if (s.consume_front("lldlto=")) { } else if (s.consume_front("lldlto=")) {
if (s.getAsInteger(10, config->ltoo) || config->ltoo > 3) if (s.getAsInteger(10, config->ltoo) || config->ltoo > 3)
error("/opt:lldlto: invalid optimization level: " + s); Err(ctx) << "/opt:lldlto: invalid optimization level: " << s;
} else if (s.consume_front("lldltocgo=")) { } else if (s.consume_front("lldltocgo=")) {
config->ltoCgo.emplace(); config->ltoCgo.emplace();
if (s.getAsInteger(10, *config->ltoCgo) || *config->ltoCgo > 3) if (s.getAsInteger(10, *config->ltoCgo) || *config->ltoCgo > 3)
error("/opt:lldltocgo: invalid codegen optimization level: " + s); Err(ctx) << "/opt:lldltocgo: invalid codegen optimization level: "
<< s;
} else if (s.consume_front("lldltojobs=")) { } else if (s.consume_front("lldltojobs=")) {
if (!get_threadpool_strategy(s)) if (!get_threadpool_strategy(s))
error("/opt:lldltojobs: invalid job count: " + s); Err(ctx) << "/opt:lldltojobs: invalid job count: " << s;
config->thinLTOJobs = s.str(); config->thinLTOJobs = s.str();
} else if (s.consume_front("lldltopartitions=")) { } else if (s.consume_front("lldltopartitions=")) {
if (s.getAsInteger(10, config->ltoPartitions) || if (s.getAsInteger(10, config->ltoPartitions) ||
config->ltoPartitions == 0) config->ltoPartitions == 0)
error("/opt:lldltopartitions: invalid partition count: " + s); Err(ctx) << "/opt:lldltopartitions: invalid partition count: " << s;
} else if (s != "lbr" && s != "nolbr") } else if (s != "lbr" && s != "nolbr")
error("/opt: unknown option: " + s); Err(ctx) << "/opt: unknown option: " << s;
} }
} }
@ -2049,7 +2055,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (llvm::is_contained(lldsaveTempsValues, s)) if (llvm::is_contained(lldsaveTempsValues, s))
config->saveTempsArgs.insert(s); config->saveTempsArgs.insert(s);
else else
error("unknown /lldsavetemps value: " + s); Err(ctx) << "unknown /lldsavetemps value: " << s;
} }
} }
@ -2063,7 +2069,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
else if (s == "asm") else if (s == "asm")
config->emit = EmitKind::ASM; config->emit = EmitKind::ASM;
else else
error("/lldemit: unknown option: " + s); Err(ctx) << "/lldemit: unknown option: " << s;
} }
// Handle /kill-at // Handle /kill-at
@ -2114,7 +2120,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (auto *arg = args.getLastArg(OPT_align)) { if (auto *arg = args.getLastArg(OPT_align)) {
parseNumbers(arg->getValue(), &config->align); parseNumbers(arg->getValue(), &config->align);
if (!isPowerOf2_64(config->align)) if (!isPowerOf2_64(config->align))
error("/align: not a power of two: " + StringRef(arg->getValue())); Err(ctx) << "/align: not a power of two: " << StringRef(arg->getValue());
if (!args.hasArg(OPT_driver)) if (!args.hasArg(OPT_driver))
Warn(ctx) << "/align specified without /driver; image may not run"; Warn(ctx) << "/align specified without /driver; image may not run";
} }
@ -2162,9 +2168,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
args.getLastArgValue(OPT_thinlto_index_only_arg); args.getLastArgValue(OPT_thinlto_index_only_arg);
std::tie(config->thinLTOPrefixReplaceOld, config->thinLTOPrefixReplaceNew, std::tie(config->thinLTOPrefixReplaceOld, config->thinLTOPrefixReplaceNew,
config->thinLTOPrefixReplaceNativeObject) = config->thinLTOPrefixReplaceNativeObject) =
getOldNewOptionsExtra(args, OPT_thinlto_prefix_replace); getOldNewOptionsExtra(ctx, args, OPT_thinlto_prefix_replace);
config->thinLTOObjectSuffixReplace = config->thinLTOObjectSuffixReplace =
getOldNewOptions(args, OPT_thinlto_object_suffix_replace); getOldNewOptions(ctx, args, OPT_thinlto_object_suffix_replace);
config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path); config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path);
config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate);
config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file);
@ -2258,12 +2264,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
switch (arg->getOption().getID()) { switch (arg->getOption().getID()) {
case OPT_end_lib: case OPT_end_lib:
if (!inLib) if (!inLib)
error("stray " + arg->getSpelling()); Err(ctx) << "stray " << arg->getSpelling();
inLib = false; inLib = false;
break; break;
case OPT_start_lib: case OPT_start_lib:
if (inLib) if (inLib)
error("nested " + arg->getSpelling()); Err(ctx) << "nested " << arg->getSpelling();
inLib = true; inLib = true;
break; break;
case OPT_wholearchive_file: case OPT_wholearchive_file:
@ -2355,8 +2361,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (!config->dynamicBase && if (!config->dynamicBase &&
(config->machine == ARMNT || isAnyArm64(config->machine))) (config->machine == ARMNT || isAnyArm64(config->machine)))
error("/dynamicbase:no is not compatible with " + Err(ctx) << "/dynamicbase:no is not compatible with "
machineToStr(config->machine)); << machineToStr(config->machine);
// Handle /export // Handle /export
{ {
@ -2446,7 +2452,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Fail early if an output file is not writable. // Fail early if an output file is not writable.
if (auto e = tryCreateFile(config->outputFile)) { if (auto e = tryCreateFile(config->outputFile)) {
error("cannot open output file " + config->outputFile + ": " + e.message()); Err(ctx) << "cannot open output file " << config->outputFile << ": "
<< e.message();
return; return;
} }
@ -2459,7 +2466,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (s == "exports") if (s == "exports")
config->mapInfo = true; config->mapInfo = true;
else else
error("unknown option: /mapinfo:" + s); Err(ctx) << "unknown option: /mapinfo:" << s;
} }
} }
@ -2774,7 +2781,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// functions. // functions.
if (auto *arg = args.getLastArg(OPT_order)) { if (auto *arg = args.getLastArg(OPT_order)) {
if (args.hasArg(OPT_call_graph_ordering_file)) if (args.hasArg(OPT_call_graph_ordering_file))
error("/order and /call-graph-order-file may not be used together"); Err(ctx) << "/order and /call-graph-order-file may not be used together";
parseOrderFile(arg->getValue()); parseOrderFile(arg->getValue());
config->callGraphProfileSort = false; config->callGraphProfileSort = false;
} }

View File

@ -179,11 +179,11 @@ void LinkerDriver::parseMerge(StringRef s) {
void LinkerDriver::parsePDBPageSize(StringRef s) { void LinkerDriver::parsePDBPageSize(StringRef s) {
int v; int v;
if (s.getAsInteger(0, v)) { if (s.getAsInteger(0, v)) {
error("/pdbpagesize: invalid argument: " + s); Err(ctx) << "/pdbpagesize: invalid argument: " << s;
return; return;
} }
if (v != 4096 && v != 8192 && v != 16384 && v != 32768) { if (v != 4096 && v != 8192 && v != 16384 && v != 32768) {
error("/pdbpagesize: invalid argument: " + s); Err(ctx) << "/pdbpagesize: invalid argument: " << s;
return; return;
} }
@ -234,12 +234,12 @@ void LinkerDriver::parseSection(StringRef s) {
void LinkerDriver::parseAligncomm(StringRef s) { void LinkerDriver::parseAligncomm(StringRef s) {
auto [name, align] = s.split(','); auto [name, align] = s.split(',');
if (name.empty() || align.empty()) { if (name.empty() || align.empty()) {
error("/aligncomm: invalid argument: " + s); Err(ctx) << "/aligncomm: invalid argument: " << s;
return; return;
} }
int v; int v;
if (align.getAsInteger(0, v)) { if (align.getAsInteger(0, v)) {
error("/aligncomm: invalid argument: " + s); Err(ctx) << "/aligncomm: invalid argument: " << s;
return; return;
} }
ctx.config.alignComm[std::string(name)] = ctx.config.alignComm[std::string(name)] =
@ -252,7 +252,7 @@ void LinkerDriver::parseFunctionPadMin(llvm::opt::Arg *a) {
if (!arg.empty()) { if (!arg.empty()) {
// Optional padding in bytes is given. // Optional padding in bytes is given.
if (arg.getAsInteger(0, ctx.config.functionPadMin)) if (arg.getAsInteger(0, ctx.config.functionPadMin))
error("/functionpadmin: invalid argument: " + arg); Err(ctx) << "/functionpadmin: invalid argument: " << arg;
return; return;
} }
// No optional argument given. // No optional argument given.
@ -263,7 +263,7 @@ void LinkerDriver::parseFunctionPadMin(llvm::opt::Arg *a) {
} else if (ctx.config.machine == AMD64) { } else if (ctx.config.machine == AMD64) {
ctx.config.functionPadMin = 6; ctx.config.functionPadMin = 6;
} else { } else {
error("/functionpadmin: invalid argument for this machine: " + arg); Err(ctx) << "/functionpadmin: invalid argument for this machine: " << arg;
} }
} }
@ -272,12 +272,12 @@ void LinkerDriver::parseDependentLoadFlags(llvm::opt::Arg *a) {
StringRef arg = a->getNumValues() ? a->getValue() : ""; StringRef arg = a->getNumValues() ? a->getValue() : "";
if (!arg.empty()) { if (!arg.empty()) {
if (arg.getAsInteger(0, ctx.config.dependentLoadFlags)) if (arg.getAsInteger(0, ctx.config.dependentLoadFlags))
error("/dependentloadflag: invalid argument: " + arg); Err(ctx) << "/dependentloadflag: invalid argument: " << arg;
return; return;
} }
// MSVC linker reports error "no argument specified", although MSDN describes // MSVC linker reports error "no argument specified", although MSDN describes
// argument as optional. // argument as optional.
error("/dependentloadflag: no argument specified"); Err(ctx) << "/dependentloadflag: no argument specified";
} }
// Parses a string in the form of "EMBED[,=<integer>]|NO". // Parses a string in the form of "EMBED[,=<integer>]|NO".
@ -334,12 +334,12 @@ void LinkerDriver::parseSwaprun(StringRef arg) {
else if (swaprun.equals_insensitive("net")) else if (swaprun.equals_insensitive("net"))
ctx.config.swaprunNet = true; ctx.config.swaprunNet = true;
else if (swaprun.empty()) else if (swaprun.empty())
error("/swaprun: missing argument"); Err(ctx) << "/swaprun: missing argument";
else else
error("/swaprun: invalid argument: " + swaprun); Err(ctx) << "/swaprun: invalid argument: " << swaprun;
// To catch trailing commas, e.g. `/spawrun:cd,` // To catch trailing commas, e.g. `/spawrun:cd,`
if (newArg.empty() && arg.ends_with(",")) if (newArg.empty() && arg.ends_with(","))
error("/swaprun: missing argument"); Err(ctx) << "/swaprun: missing argument";
arg = newArg; arg = newArg;
} while (!arg.empty()); } while (!arg.empty());
} }
@ -614,7 +614,7 @@ Export LinkerDriver::parseExport(StringRef arg) {
if (!rest.empty() && !rest.contains(',')) if (!rest.empty() && !rest.contains(','))
e.exportAs = rest; e.exportAs = rest;
else else
error("invalid EXPORTAS value: " + rest); Err(ctx) << "invalid EXPORTAS value: " << rest;
break; break;
} }
if (tok.starts_with("@")) { if (tok.starts_with("@")) {
@ -824,7 +824,7 @@ MemoryBufferRef LinkerDriver::convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
if (ctx.config.forceMultipleRes) if (ctx.config.forceMultipleRes)
Warn(ctx) << dupeDiag; Warn(ctx) << dupeDiag;
else else
error(dupeDiag); Err(ctx) << dupeDiag;
Expected<std::unique_ptr<MemoryBuffer>> e = Expected<std::unique_ptr<MemoryBuffer>> e =
llvm::object::writeWindowsResourceCOFF(ctx.config.machine, parser, llvm::object::writeWindowsResourceCOFF(ctx.config.machine, parser,
@ -875,7 +875,7 @@ static void handleColorDiagnostics(COFFLinkerContext &ctx,
else if (s == "never") else if (s == "never")
ctx.e.errs().enable_colors(false); ctx.e.errs().enable_colors(false);
else if (s != "auto") else if (s != "auto")
error("unknown option: --color-diagnostics=" + s); Err(ctx) << "unknown option: --color-diagnostics=" << s;
} }
} }

View File

@ -187,7 +187,7 @@ struct ECMapEntry {
void ObjFile::initializeECThunks() { void ObjFile::initializeECThunks() {
for (SectionChunk *chunk : hybmpChunks) { for (SectionChunk *chunk : hybmpChunks) {
if (chunk->getContents().size() % sizeof(ECMapEntry)) { if (chunk->getContents().size() % sizeof(ECMapEntry)) {
error("Invalid .hybmp chunk size " + Twine(chunk->getContents().size())); Err(ctx) << "Invalid .hybmp chunk size " << chunk->getContents().size();
continue; continue;
} }
@ -363,9 +363,9 @@ void ObjFile::readAssociativeDefinition(COFFSymbolRef sym,
const coff_section *parentSec = getSection(parentIndex); const coff_section *parentSec = getSection(parentIndex);
if (Expected<StringRef> e = coffObj->getSectionName(parentSec)) if (Expected<StringRef> e = coffObj->getSectionName(parentSec))
parentName = *e; parentName = *e;
error(toString(this) + ": associative comdat " + name + " (sec " + Err(ctx) << toString(this) << ": associative comdat " << name << " (sec "
Twine(sectionNumber) + ") has invalid reference to section " + << sectionNumber << ") has invalid reference to section "
parentName + " (sec " + Twine(parentIndex) + ")"); << parentName << " (sec " << parentIndex << ")";
}; };
if (parent == pendingComdat) { if (parent == pendingComdat) {
@ -1325,12 +1325,12 @@ void DLLFile::parse() {
bin.release(); bin.release();
coffObj.reset(obj); coffObj.reset(obj);
} else { } else {
error(toString(this) + " is not a COFF file"); Err(ctx) << toString(this) << " is not a COFF file";
return; return;
} }
if (!coffObj->getPE32Header() && !coffObj->getPE32PlusHeader()) { if (!coffObj->getPE32Header() && !coffObj->getPE32PlusHeader()) {
error(toString(this) + " is not a PE-COFF executable"); Err(ctx) << toString(this) << " is not a PE-COFF executable";
return; return;
} }

View File

@ -66,8 +66,9 @@ void SymbolTable::addFile(InputFile *file) {
ctx.objFileInstances.push_back(f); ctx.objFileInstances.push_back(f);
} else if (auto *f = dyn_cast<BitcodeFile>(file)) { } else if (auto *f = dyn_cast<BitcodeFile>(file)) {
if (ltoCompilationDone) { if (ltoCompilationDone) {
error("LTO object file " + toString(file) + " linked in after " Err(ctx) << "LTO object file " << toString(file)
"doing LTO compilation."); << " linked in after "
"doing LTO compilation.";
} }
ctx.bitcodeFileInstances.push_back(f); ctx.bitcodeFileInstances.push_back(f);
} else if (auto *f = dyn_cast<ImportFile>(file)) { } else if (auto *f = dyn_cast<ImportFile>(file)) {
@ -81,13 +82,14 @@ void SymbolTable::addFile(InputFile *file) {
(ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN || (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN ||
(ctx.config.machineInferred && (ctx.config.machineInferred &&
(ctx.config.machine == ARM64 || ctx.config.machine == AMD64)))) { (ctx.config.machine == ARM64 || ctx.config.machine == AMD64)))) {
error(toString(file) + ": machine type arm64ec is ambiguous and cannot be " Err(ctx) << toString(file)
"inferred, use /machine:arm64ec or /machine:arm64x"); << ": machine type arm64ec is ambiguous and cannot be "
"inferred, use /machine:arm64ec or /machine:arm64x";
return; return;
} }
if (!compatibleMachineType(ctx, mt)) { if (!compatibleMachineType(ctx, mt)) {
error(toString(file) + ": machine type " + machineToStr(mt) + Err(ctx) << toString(file) << ": machine type " << machineToStr(mt)
" conflicts with " + machineToStr(ctx.config.machine)); << " conflicts with " << machineToStr(ctx.config.machine);
return; return;
} }
if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN && if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN &&
@ -624,7 +626,7 @@ void SymbolTable::initializeECThunks() {
// feasible, functions are required to be COMDAT symbols with no offset. // feasible, functions are required to be COMDAT symbols with no offset.
if (!from || !from->getChunk()->isCOMDAT() || if (!from || !from->getChunk()->isCOMDAT() ||
cast<DefinedRegular>(from)->getValue()) { cast<DefinedRegular>(from)->getValue()) {
error("non COMDAT symbol '" + from->getName() + "' in hybrid map"); Err(ctx) << "non COMDAT symbol '" << from->getName() << "' in hybrid map";
continue; continue;
} }
from->getChunk()->setEntryThunk(to); from->getChunk()->setEntryThunk(to);
@ -819,7 +821,7 @@ void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,
if (ctx.config.forceMultiple) if (ctx.config.forceMultiple)
Warn(ctx) << msg; Warn(ctx) << msg;
else else
error(msg); Err(ctx) << msg;
} }
Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) { Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {

View File

@ -1644,7 +1644,7 @@ void Writer::assignAddresses() {
rawSize = alignTo(virtualSize, config->fileAlign); rawSize = alignTo(virtualSize, config->fileAlign);
} }
if (virtualSize > UINT32_MAX) if (virtualSize > UINT32_MAX)
error("section larger than 4 GiB: " + sec->name); Err(ctx) << "section larger than 4 GiB: " << sec->name;
sec->header.VirtualSize = virtualSize; sec->header.VirtualSize = virtualSize;
sec->header.SizeOfRawData = rawSize; sec->header.SizeOfRawData = rawSize;
if (rawSize != 0) if (rawSize != 0)
@ -1896,7 +1896,8 @@ void Writer::createSEHTable() {
SymbolRVASet handlers; SymbolRVASet handlers;
for (ObjFile *file : ctx.objFileInstances) { for (ObjFile *file : ctx.objFileInstances) {
if (!file->hasSafeSEH()) if (!file->hasSafeSEH())
error("/safeseh: " + file->getName() + " is not compatible with SEH"); Err(ctx) << "/safeseh: " << file->getName()
<< " is not compatible with SEH";
markSymbolsForRVATable(file, file->getSXDataChunks(), handlers); markSymbolsForRVATable(file, file->getSXDataChunks(), handlers);
} }
@ -2238,8 +2239,8 @@ void Writer::createRuntimePseudoRelocs() {
// Not writing any pseudo relocs; if some were needed, error out and // Not writing any pseudo relocs; if some were needed, error out and
// indicate what required them. // indicate what required them.
for (const RuntimePseudoReloc &rpr : rels) for (const RuntimePseudoReloc &rpr : rels)
error("automatic dllimport of " + rpr.sym->getName() + " in " + Err(ctx) << "automatic dllimport of " << rpr.sym->getName() << " in "
toString(rpr.target->file) + " requires pseudo relocations"); << toString(rpr.target->file) << " requires pseudo relocations";
return; return;
} }
@ -2249,9 +2250,10 @@ void Writer::createRuntimePseudoRelocs() {
const char *symbolName = "_pei386_runtime_relocator"; const char *symbolName = "_pei386_runtime_relocator";
Symbol *relocator = ctx.symtab.findUnderscore(symbolName); Symbol *relocator = ctx.symtab.findUnderscore(symbolName);
if (!relocator) if (!relocator)
error("output image has runtime pseudo relocations, but the function " + Err(ctx)
Twine(symbolName) + << "output image has runtime pseudo relocations, but the function "
" is missing; it is needed for fixing the relocations at runtime"); << symbolName
<< " is missing; it is needed for fixing the relocations at runtime";
} }
PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels); PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels);