[llvm][clang] Pass VFS to llvm::cl command line handling (#159174)
This PR passes the VFS down to `llvm::cl` functions so that they don't assume the real file system.
This commit is contained in:
parent
cfaf23927c
commit
152a2162a1
@ -775,8 +775,8 @@ It should be used via an editor plugin rather than invoked directly. For more in
|
||||
clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable.
|
||||
)";
|
||||
llvm::cl::HideUnrelatedOptions(ClangdCategories);
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, Overview,
|
||||
/*Errs=*/nullptr, FlagsEnvVar);
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, Overview, /*Errs=*/nullptr,
|
||||
/*VFS=*/nullptr, FlagsEnvVar);
|
||||
if (Test) {
|
||||
if (!Sync.getNumOccurrences())
|
||||
Sync = true;
|
||||
|
||||
@ -562,7 +562,8 @@ getInstrProfOptions(const CodeGenOptions &CodeGenOpts,
|
||||
return Options;
|
||||
}
|
||||
|
||||
static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts) {
|
||||
static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts,
|
||||
vfs::FileSystem &VFS) {
|
||||
SmallVector<const char *, 16> BackendArgs;
|
||||
BackendArgs.push_back("clang"); // Fake program name.
|
||||
if (!CodeGenOpts.DebugPass.empty()) {
|
||||
@ -582,8 +583,9 @@ static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts) {
|
||||
// FIXME: The command line parser below is not thread-safe and shares a global
|
||||
// state, so this call might crash or overwrite the options of another Clang
|
||||
// instance in the same process.
|
||||
llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
|
||||
BackendArgs.data());
|
||||
llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, BackendArgs.data(),
|
||||
/*Overview=*/"", /*Errs=*/nullptr,
|
||||
/*VFS=*/&VFS);
|
||||
}
|
||||
|
||||
void EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
|
||||
@ -1260,7 +1262,7 @@ void EmitAssemblyHelper::RunCodegenPipeline(
|
||||
void EmitAssemblyHelper::emitAssembly(BackendAction Action,
|
||||
std::unique_ptr<raw_pwrite_stream> OS,
|
||||
BackendConsumer *BC) {
|
||||
setCommandLineOpts(CodeGenOpts);
|
||||
setCommandLineOpts(CodeGenOpts, CI.getVirtualFileSystem());
|
||||
|
||||
bool RequiresCodeGen = actionRequiresCodeGen(Action);
|
||||
CreateTargetMachine(RequiresCodeGen);
|
||||
@ -1295,7 +1297,7 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex,
|
||||
ModuleToDefinedGVSummaries;
|
||||
CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
|
||||
|
||||
setCommandLineOpts(CGOpts);
|
||||
setCommandLineOpts(CGOpts, CI.getVirtualFileSystem());
|
||||
|
||||
// We can simply import the values mentioned in the combined index, since
|
||||
// we should only invoke this using the individual indexes written out
|
||||
|
||||
@ -244,7 +244,9 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
|
||||
Args[NumArgs + 1] = nullptr;
|
||||
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
|
||||
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get(), /*Overview=*/"",
|
||||
/*Errs=*/nullptr,
|
||||
/*VFS=*/&Clang->getVirtualFileSystem());
|
||||
}
|
||||
|
||||
#if CLANG_ENABLE_STATIC_ANALYZER
|
||||
|
||||
@ -669,6 +669,8 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
|
||||
DiagClient->setPrefix("clang -cc1as");
|
||||
DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, DiagClient);
|
||||
|
||||
auto VFS = vfs::getRealFileSystem();
|
||||
|
||||
// Set an error handler, so that any LLVM backend diagnostics go through our
|
||||
// error handler.
|
||||
ScopedFatalErrorHandler FatalErrorHandler
|
||||
@ -707,7 +709,8 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
Args[i + 1] = Asm.LLVMArgs[i].c_str();
|
||||
Args[NumArgs + 1] = nullptr;
|
||||
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
|
||||
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get(), /*Overview=*/"",
|
||||
/*Errs=*/nullptr, /*VFS=*/VFS.get());
|
||||
}
|
||||
|
||||
// Execute the invocation, unless there were parsing errors.
|
||||
|
||||
@ -204,7 +204,8 @@ static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
|
||||
}
|
||||
|
||||
static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
|
||||
const llvm::ToolContext &ToolContext) {
|
||||
const llvm::ToolContext &ToolContext,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
|
||||
// If we call the cc1 tool from the clangDriver library (through
|
||||
// Driver::CC1Main), we need to clean up the options usage count. The options
|
||||
// are currently global, and they might have been used previously by the
|
||||
@ -212,7 +213,8 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
|
||||
llvm::cl::ResetAllOptionOccurrences();
|
||||
|
||||
llvm::BumpPtrAllocator A;
|
||||
llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine);
|
||||
llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine,
|
||||
VFS.get());
|
||||
if (llvm::Error Err = ECtx.expandResponseFiles(ArgV)) {
|
||||
llvm::errs() << toString(std::move(Err)) << '\n';
|
||||
return 1;
|
||||
@ -254,14 +256,16 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
|
||||
bool ClangCLMode =
|
||||
IsClangCL(getDriverMode(ProgName, llvm::ArrayRef(Args).slice(1)));
|
||||
|
||||
if (llvm::Error Err = expandResponseFiles(Args, ClangCLMode, A)) {
|
||||
auto VFS = llvm::vfs::getRealFileSystem();
|
||||
|
||||
if (llvm::Error Err = expandResponseFiles(Args, ClangCLMode, A, VFS.get())) {
|
||||
llvm::errs() << toString(std::move(Err)) << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Handle -cc1 integrated tools.
|
||||
if (Args.size() >= 2 && StringRef(Args[1]).starts_with("-cc1"))
|
||||
return ExecuteCC1Tool(Args, ToolContext);
|
||||
return ExecuteCC1Tool(Args, ToolContext, VFS);
|
||||
|
||||
// Handle options that need handling before the real command line parsing in
|
||||
// Driver::BuildCompilation()
|
||||
@ -341,7 +345,6 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
|
||||
Diags.takeClient(), std::move(SerializedConsumer)));
|
||||
}
|
||||
|
||||
auto VFS = llvm::vfs::getRealFileSystem();
|
||||
ProcessWarningOptions(Diags, *DiagOpts, *VFS, /*ReportDiags=*/false);
|
||||
|
||||
Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags,
|
||||
@ -361,10 +364,10 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
|
||||
if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver))
|
||||
return 1;
|
||||
|
||||
auto ExecuteCC1WithContext =
|
||||
[&ToolContext](SmallVectorImpl<const char *> &ArgV) {
|
||||
return ExecuteCC1Tool(ArgV, ToolContext);
|
||||
};
|
||||
auto ExecuteCC1WithContext = [&ToolContext,
|
||||
&VFS](SmallVectorImpl<const char *> &ArgV) {
|
||||
return ExecuteCC1Tool(ArgV, ToolContext, VFS);
|
||||
};
|
||||
if (!UseNewCC1Process) {
|
||||
TheDriver.CC1Main = ExecuteCC1WithContext;
|
||||
// Ensure the CC1Command actually catches cc1 crashes
|
||||
|
||||
@ -69,6 +69,7 @@ namespace cl {
|
||||
LLVM_ABI bool ParseCommandLineOptions(int argc, const char *const *argv,
|
||||
StringRef Overview = "",
|
||||
raw_ostream *Errs = nullptr,
|
||||
vfs::FileSystem *VFS = nullptr,
|
||||
const char *EnvVar = nullptr,
|
||||
bool LongOptionsUseDoubleDash = false);
|
||||
|
||||
@ -2192,7 +2193,8 @@ class ExpansionContext {
|
||||
SmallVectorImpl<const char *> &NewArgv);
|
||||
|
||||
public:
|
||||
LLVM_ABI ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T);
|
||||
LLVM_ABI ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T,
|
||||
vfs::FileSystem *FS = nullptr);
|
||||
|
||||
ExpansionContext &setMarkEOLs(bool X) {
|
||||
MarkEOLs = X;
|
||||
|
||||
@ -188,6 +188,7 @@ public:
|
||||
|
||||
bool ParseCommandLineOptions(int argc, const char *const *argv,
|
||||
StringRef Overview, raw_ostream *Errs = nullptr,
|
||||
vfs::FileSystem *VFS = nullptr,
|
||||
bool LongOptionsUseDoubleDash = false);
|
||||
|
||||
void forEachSubCommand(Option &Opt, function_ref<void(SubCommand &)> Action) {
|
||||
@ -1401,8 +1402,9 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
|
||||
return true;
|
||||
}
|
||||
|
||||
ExpansionContext::ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T)
|
||||
: Saver(A), Tokenizer(T), FS(vfs::getRealFileSystem().get()) {}
|
||||
ExpansionContext::ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T,
|
||||
vfs::FileSystem *FS)
|
||||
: Saver(A), Tokenizer(T), FS(FS ? FS : vfs::getRealFileSystem().get()) {}
|
||||
|
||||
bool ExpansionContext::findConfigFile(StringRef FileName,
|
||||
SmallVectorImpl<char> &FilePath) {
|
||||
@ -1461,7 +1463,7 @@ Error ExpansionContext::readConfigFile(StringRef CfgFile,
|
||||
static void initCommonOptions();
|
||||
bool cl::ParseCommandLineOptions(int argc, const char *const *argv,
|
||||
StringRef Overview, raw_ostream *Errs,
|
||||
const char *EnvVar,
|
||||
vfs::FileSystem *VFS, const char *EnvVar,
|
||||
bool LongOptionsUseDoubleDash) {
|
||||
initCommonOptions();
|
||||
SmallVector<const char *, 20> NewArgv;
|
||||
@ -1482,8 +1484,8 @@ bool cl::ParseCommandLineOptions(int argc, const char *const *argv,
|
||||
int NewArgc = static_cast<int>(NewArgv.size());
|
||||
|
||||
// Parse all options.
|
||||
return GlobalParser->ParseCommandLineOptions(NewArgc, &NewArgv[0], Overview,
|
||||
Errs, LongOptionsUseDoubleDash);
|
||||
return GlobalParser->ParseCommandLineOptions(
|
||||
NewArgc, &NewArgv[0], Overview, Errs, VFS, LongOptionsUseDoubleDash);
|
||||
}
|
||||
|
||||
/// Reset all options at least once, so that we can parse different options.
|
||||
@ -1503,17 +1505,17 @@ void CommandLineParser::ResetAllOptionOccurrences() {
|
||||
}
|
||||
}
|
||||
|
||||
bool CommandLineParser::ParseCommandLineOptions(int argc,
|
||||
const char *const *argv,
|
||||
StringRef Overview,
|
||||
raw_ostream *Errs,
|
||||
bool LongOptionsUseDoubleDash) {
|
||||
bool CommandLineParser::ParseCommandLineOptions(
|
||||
int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs,
|
||||
vfs::FileSystem *VFS, bool LongOptionsUseDoubleDash) {
|
||||
assert(hasOptions() && "No options specified!");
|
||||
|
||||
ProgramOverview = Overview;
|
||||
bool IgnoreErrors = Errs;
|
||||
if (!Errs)
|
||||
Errs = &errs();
|
||||
if (!VFS)
|
||||
VFS = vfs::getRealFileSystem().get();
|
||||
bool ErrorParsing = false;
|
||||
|
||||
// Expand response files.
|
||||
@ -1524,7 +1526,7 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
|
||||
#else
|
||||
auto Tokenize = cl::TokenizeGNUCommandLine;
|
||||
#endif
|
||||
ExpansionContext ECtx(A, Tokenize);
|
||||
ExpansionContext ECtx(A, Tokenize, VFS);
|
||||
if (Error Err = ECtx.expandResponseFiles(newArgv)) {
|
||||
*Errs << toString(std::move(Err)) << '\n';
|
||||
return false;
|
||||
|
||||
@ -104,7 +104,7 @@ int main(int argc, char *argv[]) {
|
||||
cl::HideUnrelatedOptions(Cat);
|
||||
cl::ParseCommandLineOptions(
|
||||
argc, argv, "Dump a YAML description from an object file", nullptr,
|
||||
nullptr, /*LongOptionsUseDoubleDash=*/true);
|
||||
nullptr, nullptr, /*LongOptionsUseDoubleDash=*/true);
|
||||
|
||||
std::error_code EC;
|
||||
std::unique_ptr<ToolOutputFile> Out(
|
||||
|
||||
@ -115,7 +115,7 @@ int main(int argc, char **argv) {
|
||||
cl::HideUnrelatedOptions(Cat);
|
||||
cl::ParseCommandLineOptions(
|
||||
argc, argv, "Create an object file from a YAML description", nullptr,
|
||||
nullptr, /*LongOptionsUseDoubleDash=*/true);
|
||||
nullptr, nullptr, /*LongOptionsUseDoubleDash=*/true);
|
||||
|
||||
constexpr StringRef ProgName = "yaml2obj";
|
||||
auto ErrHandler = [&](const Twine &Msg) {
|
||||
|
||||
@ -1915,20 +1915,20 @@ TEST(CommandLineTest, LongOptions) {
|
||||
|
||||
// Fails because `-ab` is treated as `-a -b`, so `-a` is seen twice, and
|
||||
// `val1` is unexpected.
|
||||
EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(),
|
||||
&OS, nullptr, true));
|
||||
EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(), &OS, nullptr,
|
||||
nullptr, true));
|
||||
EXPECT_FALSE(Errs.empty()); Errs.clear();
|
||||
cl::ResetAllOptionOccurrences();
|
||||
|
||||
// Works because `-a` is treated differently than `--ab`.
|
||||
EXPECT_TRUE(cl::ParseCommandLineOptions(4, args2, StringRef(),
|
||||
&OS, nullptr, true));
|
||||
EXPECT_TRUE(cl::ParseCommandLineOptions(4, args2, StringRef(), &OS, nullptr,
|
||||
nullptr, true));
|
||||
EXPECT_TRUE(Errs.empty()); Errs.clear();
|
||||
cl::ResetAllOptionOccurrences();
|
||||
|
||||
// Works because `-ab` is treated as `-a -b`, and `--ab` is a long option.
|
||||
EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(),
|
||||
&OS, nullptr, true));
|
||||
EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(), &OS, nullptr,
|
||||
nullptr, true));
|
||||
EXPECT_TRUE(OptA);
|
||||
EXPECT_TRUE(OptBLong);
|
||||
EXPECT_STREQ("val1", OptAB.c_str());
|
||||
|
||||
@ -735,7 +735,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
InitLLVM X(argc, argv);
|
||||
cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
|
||||
"FILECHECK_OPTS");
|
||||
/*VFS*/ nullptr, "FILECHECK_OPTS");
|
||||
|
||||
// Select -dump-input* values. The -help documentation specifies the default
|
||||
// value and which value to choose if an option is specified multiple times.
|
||||
|
||||
@ -148,6 +148,7 @@ int main(int argc, const char **argv) {
|
||||
"Split input into multiple parts separated by regex '^(.|//)--- ' and "
|
||||
"extract the part specified by '^(.|//)--- <part>'\n",
|
||||
nullptr,
|
||||
/*VFS=*/nullptr,
|
||||
/*EnvVar=*/nullptr,
|
||||
/*LongOptionsUseDoubleDash=*/true);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user