summaryrefslogtreecommitdiffstats
path: root/tools/driver/driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/driver/driver.cpp')
-rw-r--r--tools/driver/driver.cpp394
1 files changed, 226 insertions, 168 deletions
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 9f93837..e1f9367 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -18,7 +18,9 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
+#include "clang/Frontend/ChainedDiagnosticConsumer.h"
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "llvm/ADT/ArrayRef.h"
@@ -61,8 +63,8 @@ std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
return llvm::sys::fs::getMainExecutable(Argv0, P);
}
-static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
- StringRef S) {
+static const char *GetStableCStr(std::set<std::string> &SavedStrings,
+ StringRef S) {
return SavedStrings.insert(S).first->c_str();
}
@@ -101,12 +103,12 @@ static void ApplyOneQAOverride(raw_ostream &OS,
if (Edit[0] == '^') {
const char *Str =
- SaveStringInSet(SavedStrings, Edit.substr(1));
+ GetStableCStr(SavedStrings, Edit.substr(1));
OS << "### Adding argument " << Str << " at beginning\n";
Args.insert(Args.begin() + 1, Str);
} else if (Edit[0] == '+') {
const char *Str =
- SaveStringInSet(SavedStrings, Edit.substr(1));
+ GetStableCStr(SavedStrings, Edit.substr(1));
OS << "### Adding argument " << Str << " at end\n";
Args.push_back(Str);
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
@@ -116,11 +118,14 @@ static void ApplyOneQAOverride(raw_ostream &OS,
ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
+ // Ignore end-of-line response file markers
+ if (Args[i] == nullptr)
+ continue;
std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
if (Repl != Args[i]) {
OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
- Args[i] = SaveStringInSet(SavedStrings, Repl);
+ Args[i] = GetStableCStr(SavedStrings, Repl);
}
}
} else if (Edit[0] == 'x' || Edit[0] == 'X') {
@@ -142,6 +147,9 @@ static void ApplyOneQAOverride(raw_ostream &OS,
} else if (Edit[0] == 'O') {
for (unsigned i = 1; i < Args.size();) {
const char *A = Args[i];
+ // Ignore end-of-line response file markers
+ if (A == nullptr)
+ continue;
if (A[0] == '-' && A[1] == 'O' &&
(A[2] == '\0' ||
(A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
@@ -152,7 +160,7 @@ static void ApplyOneQAOverride(raw_ostream &OS,
++i;
}
OS << "### Adding argument " << Edit << " at end\n";
- Args.push_back(SaveStringInSet(SavedStrings, '-' + Edit.str()));
+ Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
} else {
OS << "### Unrecognized edit: " << Edit << "\n";
}
@@ -187,97 +195,98 @@ static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
}
}
-extern int cc1_main(const char **ArgBegin, const char **ArgEnd,
- const char *Argv0, void *MainAddr);
-extern int cc1as_main(const char **ArgBegin, const char **ArgEnd,
- const char *Argv0, void *MainAddr);
+extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
+ void *MainAddr);
+extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
+ void *MainAddr);
+
+struct DriverSuffix {
+ const char *Suffix;
+ const char *ModeFlag;
+};
+
+static const DriverSuffix *FindDriverSuffix(StringRef ProgName) {
+ // A list of known driver suffixes. Suffixes are compared against the
+ // program name in order. If there is a match, the frontend type if updated as
+ // necessary by applying the ModeFlag.
+ static const DriverSuffix DriverSuffixes[] = {
+ {"clang", nullptr},
+ {"clang++", "--driver-mode=g++"},
+ {"clang-c++", "--driver-mode=g++"},
+ {"clang-cc", nullptr},
+ {"clang-cpp", "--driver-mode=cpp"},
+ {"clang-g++", "--driver-mode=g++"},
+ {"clang-gcc", nullptr},
+ {"clang-cl", "--driver-mode=cl"},
+ {"cc", nullptr},
+ {"cpp", "--driver-mode=cpp"},
+ {"cl", "--driver-mode=cl"},
+ {"++", "--driver-mode=g++"},
+ };
+
+ for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i)
+ if (ProgName.endswith(DriverSuffixes[i].Suffix))
+ return &DriverSuffixes[i];
+ return nullptr;
+}
static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
- std::set<std::string> &SavedStrings,
- Driver &TheDriver)
-{
- // Try to infer frontend type and default target from the program name.
-
- // suffixes[] contains the list of known driver suffixes.
- // Suffixes are compared against the program name in order.
- // If there is a match, the frontend type is updated as necessary (CPP/C++).
- // If there is no match, a second round is done after stripping the last
- // hyphen and everything following it. This allows using something like
- // "clang++-2.9".
-
- // If there is a match in either the first or second round,
- // the function tries to identify a target as prefix. E.g.
- // "x86_64-linux-clang" as interpreted as suffix "clang" with
- // target prefix "x86_64-linux". If such a target prefix is found,
- // is gets added via -target as implicit first argument.
- static const struct {
- const char *Suffix;
- const char *ModeFlag;
- } suffixes [] = {
- { "clang", nullptr },
- { "clang++", "--driver-mode=g++" },
- { "clang-c++", "--driver-mode=g++" },
- { "clang-cc", nullptr },
- { "clang-cpp", "--driver-mode=cpp" },
- { "clang-g++", "--driver-mode=g++" },
- { "clang-gcc", nullptr },
- { "clang-cl", "--driver-mode=cl" },
- { "cc", nullptr },
- { "cpp", "--driver-mode=cpp" },
- { "cl" , "--driver-mode=cl" },
- { "++", "--driver-mode=g++" },
- };
- std::string ProgName(llvm::sys::path::stem(ArgVector[0]));
+ std::set<std::string> &SavedStrings) {
+ // Try to infer frontend type and default target from the program name by
+ // comparing it against DriverSuffixes in order.
+
+ // If there is a match, the function tries to identify a target as prefix.
+ // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target
+ // prefix "x86_64-linux". If such a target prefix is found, is gets added via
+ // -target as implicit first argument.
+
+ std::string ProgName =llvm::sys::path::stem(ArgVector[0]);
#ifdef LLVM_ON_WIN32
// Transform to lowercase for case insensitive file systems.
- std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(),
- toLowercase);
+ ProgName = StringRef(ProgName).lower();
#endif
- StringRef ProgNameRef(ProgName);
- StringRef Prefix;
-
- for (int Components = 2; Components; --Components) {
- bool FoundMatch = false;
- size_t i;
-
- for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
- if (ProgNameRef.endswith(suffixes[i].Suffix)) {
- FoundMatch = true;
- SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
- if (it != ArgVector.end())
- ++it;
- if (suffixes[i].ModeFlag)
- ArgVector.insert(it, suffixes[i].ModeFlag);
- break;
- }
- }
- if (FoundMatch) {
- StringRef::size_type LastComponent = ProgNameRef.rfind('-',
- ProgNameRef.size() - strlen(suffixes[i].Suffix));
- if (LastComponent != StringRef::npos)
- Prefix = ProgNameRef.slice(0, LastComponent);
- break;
- }
+ StringRef ProgNameRef = ProgName;
+ const DriverSuffix *DS = FindDriverSuffix(ProgNameRef);
- StringRef::size_type LastComponent = ProgNameRef.rfind('-');
- if (LastComponent == StringRef::npos)
- break;
- ProgNameRef = ProgNameRef.slice(0, LastComponent);
+ if (!DS) {
+ // Try again after stripping any trailing version number:
+ // clang++3.5 -> clang++
+ ProgNameRef = ProgNameRef.rtrim("0123456789.");
+ DS = FindDriverSuffix(ProgNameRef);
}
- if (Prefix.empty())
- return;
-
- std::string IgnoredError;
- if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
- SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
- if (it != ArgVector.end())
- ++it;
- const char* Strings[] =
- { SaveStringInSet(SavedStrings, std::string("-target")),
- SaveStringInSet(SavedStrings, Prefix) };
- ArgVector.insert(it, Strings, Strings + llvm::array_lengthof(Strings));
+ if (!DS) {
+ // Try again after stripping trailing -component.
+ // clang++-tot -> clang++
+ ProgNameRef = ProgNameRef.slice(0, ProgNameRef.rfind('-'));
+ DS = FindDriverSuffix(ProgNameRef);
+ }
+
+ if (DS) {
+ if (const char *Flag = DS->ModeFlag) {
+ // Add Flag to the arguments.
+ auto it = ArgVector.begin();
+ if (it != ArgVector.end())
+ ++it;
+ ArgVector.insert(it, Flag);
+ }
+
+ StringRef::size_type LastComponent = ProgNameRef.rfind(
+ '-', ProgNameRef.size() - strlen(DS->Suffix));
+ if (LastComponent == StringRef::npos)
+ return;
+
+ // Infer target from the prefix.
+ StringRef Prefix = ProgNameRef.slice(0, LastComponent);
+ std::string IgnoredError;
+ if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
+ auto it = ArgVector.begin();
+ if (it != ArgVector.end())
+ ++it;
+ const char *arr[] = { "-target", GetStableCStr(SavedStrings, Prefix) };
+ ArgVector.insert(it, std::begin(arr), std::end(arr));
+ }
}
}
@@ -286,21 +295,97 @@ namespace {
public:
StringSetSaver(std::set<std::string> &Storage) : Storage(Storage) {}
const char *SaveString(const char *Str) override {
- return SaveStringInSet(Storage, Str);
+ return GetStableCStr(Storage, Str);
}
private:
std::set<std::string> &Storage;
};
}
+static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
+ // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
+ TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
+ if (TheDriver.CCPrintOptions)
+ TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
+
+ // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE.
+ TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS");
+ if (TheDriver.CCPrintHeaders)
+ TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
+
+ // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
+ TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
+ if (TheDriver.CCLogDiagnostics)
+ TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
+}
+
+static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
+ const std::string &Path) {
+ // If the clang binary happens to be named cl.exe for compatibility reasons,
+ // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
+ StringRef ExeBasename(llvm::sys::path::filename(Path));
+ if (ExeBasename.equals_lower("cl.exe"))
+ ExeBasename = "clang-cl.exe";
+ DiagClient->setPrefix(ExeBasename);
+}
+
+// This lets us create the DiagnosticsEngine with a properly-filled-out
+// DiagnosticOptions instance.
+static DiagnosticOptions *
+CreateAndPopulateDiagOpts(SmallVectorImpl<const char *> &argv) {
+ auto *DiagOpts = new DiagnosticOptions;
+ std::unique_ptr<OptTable> Opts(createDriverOptTable());
+ unsigned MissingArgIndex, MissingArgCount;
+ std::unique_ptr<InputArgList> Args(Opts->ParseArgs(
+ argv.begin() + 1, argv.end(), MissingArgIndex, MissingArgCount));
+ // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
+ // Any errors that would be diagnosed here will also be diagnosed later,
+ // when the DiagnosticsEngine actually exists.
+ (void) ParseDiagnosticArgs(*DiagOpts, *Args);
+ return DiagOpts;
+}
+
+static void SetInstallDir(SmallVectorImpl<const char *> &argv,
+ Driver &TheDriver) {
+ // Attempt to find the original path used to invoke the driver, to determine
+ // the installed path. We do this manually, because we want to support that
+ // path being a symlink.
+ SmallString<128> InstalledPath(argv[0]);
+
+ // Do a PATH lookup, if there are no directory components.
+ if (llvm::sys::path::filename(InstalledPath) == InstalledPath)
+ if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName(
+ llvm::sys::path::filename(InstalledPath.str())))
+ InstalledPath = *Tmp;
+ llvm::sys::fs::make_absolute(InstalledPath);
+ InstalledPath = llvm::sys::path::parent_path(InstalledPath);
+ if (llvm::sys::fs::exists(InstalledPath.c_str()))
+ TheDriver.setInstalledDir(InstalledPath);
+}
+
+static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
+ void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath;
+ if (Tool == "")
+ return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP);
+ if (Tool == "as")
+ return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP);
+
+ // Reject unknown tools.
+ llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n";
+ return 1;
+}
+
int main(int argc_, const char **argv_) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc_, argv_);
+ if (llvm::sys::Process::FixupStandardFileDescriptors())
+ return 1;
+
SmallVector<const char *, 256> argv;
llvm::SpecificBumpPtrAllocator<char> ArgAllocator;
std::error_code EC = llvm::sys::Process::GetArgumentVector(
- argv, ArrayRef<const char *>(argv_, argc_), ArgAllocator);
+ argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator);
if (EC) {
llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n';
return 1;
@@ -308,26 +393,33 @@ int main(int argc_, const char **argv_) {
std::set<std::string> SavedStrings;
StringSetSaver Saver(SavedStrings);
- llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv);
-
- // Handle -cc1 integrated tools.
- if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) {
- StringRef Tool = argv[1] + 4;
-
- if (Tool == "")
- return cc1_main(argv.data()+2, argv.data()+argv.size(), argv[0],
- (void*) (intptr_t) GetExecutablePath);
- if (Tool == "as")
- return cc1as_main(argv.data()+2, argv.data()+argv.size(), argv[0],
- (void*) (intptr_t) GetExecutablePath);
- // Reject unknown tools.
- llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n";
- return 1;
+ // Determines whether we want nullptr markers in argv to indicate response
+ // files end-of-lines. We only use this for the /LINK driver argument.
+ bool MarkEOLs = true;
+ if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1"))
+ MarkEOLs = false;
+ llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv,
+ MarkEOLs);
+
+ // Handle -cc1 integrated tools, even if -cc1 was expanded from a response
+ // file.
+ auto FirstArg = std::find_if(argv.begin() + 1, argv.end(),
+ [](const char *A) { return A != nullptr; });
+ if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) {
+ // If -cc1 came from a response file, remove the EOL sentinels.
+ if (MarkEOLs) {
+ auto newEnd = std::remove(argv.begin(), argv.end(), nullptr);
+ argv.resize(newEnd - argv.begin());
+ }
+ return ExecuteCC1Tool(argv, argv[1] + 4);
}
bool CanonicalPrefixes = true;
for (int i = 1, size = argv.size(); i < size; ++i) {
+ // Skip end-of-line response file markers
+ if (argv[i] == nullptr)
+ continue;
if (StringRef(argv[i]) == "-no-canonical-prefixes") {
CanonicalPrefixes = false;
break;
@@ -343,73 +435,34 @@ int main(int argc_, const char **argv_) {
std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes);
- IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
- {
- std::unique_ptr<OptTable> Opts(createDriverOptTable());
- unsigned MissingArgIndex, MissingArgCount;
- std::unique_ptr<InputArgList> Args(Opts->ParseArgs(
- argv.begin() + 1, argv.end(), MissingArgIndex, MissingArgCount));
- // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
- // Any errors that would be diagnosed here will also be diagnosed later,
- // when the DiagnosticsEngine actually exists.
- (void) ParseDiagnosticArgs(*DiagOpts, *Args);
- }
- // Now we can create the DiagnosticsEngine with a properly-filled-out
- // DiagnosticOptions instance.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
+ CreateAndPopulateDiagOpts(argv);
+
TextDiagnosticPrinter *DiagClient
= new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
-
- // If the clang binary happens to be named cl.exe for compatibility reasons,
- // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
- StringRef ExeBasename(llvm::sys::path::filename(Path));
- if (ExeBasename.equals_lower("cl.exe"))
- ExeBasename = "clang-cl.exe";
- DiagClient->setPrefix(ExeBasename);
+ FixupDiagPrefixExeName(DiagClient, Path);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
- ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
-
- Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
- // Attempt to find the original path used to invoke the driver, to determine
- // the installed path. We do this manually, because we want to support that
- // path being a symlink.
- {
- SmallString<128> InstalledPath(argv[0]);
-
- // Do a PATH lookup, if there are no directory components.
- if (llvm::sys::path::filename(InstalledPath) == InstalledPath) {
- std::string Tmp = llvm::sys::FindProgramByName(
- llvm::sys::path::filename(InstalledPath.str()));
- if (!Tmp.empty())
- InstalledPath = Tmp;
- }
- llvm::sys::fs::make_absolute(InstalledPath);
- InstalledPath = llvm::sys::path::parent_path(InstalledPath);
- bool exists;
- if (!llvm::sys::fs::exists(InstalledPath.str(), exists) && exists)
- TheDriver.setInstalledDir(InstalledPath);
+ if (!DiagOpts->DiagnosticSerializationFile.empty()) {
+ auto SerializedConsumer =
+ clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
+ &*DiagOpts, /*MergeChildRecords=*/true);
+ Diags.setClient(new ChainedDiagnosticConsumer(
+ Diags.takeClient(), std::move(SerializedConsumer)));
}
- llvm::InitializeAllTargets();
- ParseProgName(argv, SavedStrings, TheDriver);
+ ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
- // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
- TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
- if (TheDriver.CCPrintOptions)
- TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
+ Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
+ SetInstallDir(argv, TheDriver);
- // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE.
- TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS");
- if (TheDriver.CCPrintHeaders)
- TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
+ llvm::InitializeAllTargets();
+ ParseProgName(argv, SavedStrings);
- // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
- TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
- if (TheDriver.CCLogDiagnostics)
- TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
+ SetBackdoorDriverOutputsFromEnvVars(TheDriver);
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
int Res = 0;
@@ -420,14 +473,17 @@ int main(int argc_, const char **argv_) {
// Force a crash to test the diagnostics.
if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) {
Diags.Report(diag::err_drv_force_crash) << "FORCE_CLANG_DIAGNOSTICS_CRASH";
- const Command *FailingCommand = nullptr;
- FailingCommands.push_back(std::make_pair(-1, FailingCommand));
+
+ // Pretend that every command failed.
+ FailingCommands.clear();
+ for (const auto &J : C->getJobs())
+ if (const Command *C = dyn_cast<Command>(&J))
+ FailingCommands.push_back(std::make_pair(-1, C));
}
- for (SmallVectorImpl< std::pair<int, const Command *> >::iterator it =
- FailingCommands.begin(), ie = FailingCommands.end(); it != ie; ++it) {
- int CommandRes = it->first;
- const Command *FailingCommand = it->second;
+ for (const auto &P : FailingCommands) {
+ int CommandRes = P.first;
+ const Command *FailingCommand = P.second;
if (!Res)
Res = CommandRes;
@@ -440,15 +496,17 @@ int main(int argc_, const char **argv_) {
DiagnoseCrash |= CommandRes == 3;
#endif
if (DiagnoseCrash) {
- TheDriver.generateCompilationDiagnostics(*C, FailingCommand);
+ TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
break;
}
}
+ Diags.getClient()->finish();
+
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
llvm::TimerGroup::printAll(llvm::errs());
-
+
llvm::llvm_shutdown();
#ifdef LLVM_ON_WIN32
OpenPOWER on IntegriCloud