[clang] 11ee699 - [clang][tooling] Accept Clang invocations with multiple jobs
Jan Svoboda via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 27 01:48:04 PDT 2021
Author: Jan Svoboda
Date: 2021-07-27T10:47:55+02:00
New Revision: 11ee699b3c812ebe56ce5d3b14ab7ef16c1e8495
URL: https://github.com/llvm/llvm-project/commit/11ee699b3c812ebe56ce5d3b14ab7ef16c1e8495
DIFF: https://github.com/llvm/llvm-project/commit/11ee699b3c812ebe56ce5d3b14ab7ef16c1e8495.diff
LOG: [clang][tooling] Accept Clang invocations with multiple jobs
When `-fno-integrated-as` is passed to the Clang driver (or set by default by a specific toolchain), it will construct an assembler job in addition to the cc1 job. Similarly, the `-fembed-bitcode` driver flag will create additional cc1 job that reads LLVM IR file.
The Clang tooling library only cares about the job that reads a source file. Instead of relying on the fact that the client injected `-fsyntax-only` to the driver invocation to get a single `-cc1` invocation that reads the source file, this patch filters out such jobs from `Compilation` automatically and ignores the rest.
This fixes a test failure in `ClangScanDeps/headerwithname.cpp` and `ClangScanDeps/headerwithnamefollowedbyinclude.cpp` on AIX reported here: https://reviews.llvm.org/D103461#2841918 and `clang-scan-deps` failures with `-fembed-bitcode`.
Depends on D106788.
Reviewed By: dexonsmith
Differential Revision: https://reviews.llvm.org/D105695
Added:
Modified:
clang/include/clang/Tooling/Tooling.h
clang/lib/Tooling/Tooling.cpp
clang/unittests/Tooling/ToolingTest.cpp
Removed:
clang/test/Tooling/clang-check-offload.cpp
################################################################################
diff --git a/clang/include/clang/Tooling/Tooling.h b/clang/include/clang/Tooling/Tooling.h
index 8b3b2e5ad0026..73d09662562b2 100644
--- a/clang/include/clang/Tooling/Tooling.h
+++ b/clang/include/clang/Tooling/Tooling.h
@@ -66,6 +66,14 @@ namespace tooling {
class CompilationDatabase;
+/// Retrieves the flags of the `-cc1` job in `Compilation` that has only source
+/// files as its inputs.
+/// Returns nullptr if there are no such jobs or multiple of them. Note that
+/// offloading jobs are ignored.
+const llvm::opt::ArgStringList *
+getCC1Arguments(DiagnosticsEngine *Diagnostics,
+ driver::Compilation *Compilation);
+
/// Interface to process a clang::CompilerInvocation.
///
/// If your tool is based on FrontendAction, you should be deriving from
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 463f466d9b763..5242134097dac 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -83,16 +83,20 @@ newDriver(DiagnosticsEngine *Diagnostics, const char *BinaryName,
return CompilerDriver;
}
-/// Retrieves the clang CC1 specific flags out of the compilation's jobs.
-///
-/// Returns nullptr on error.
-static const llvm::opt::ArgStringList *getCC1Arguments(
- DiagnosticsEngine *Diagnostics, driver::Compilation *Compilation) {
- // We expect to get back exactly one Command job, if we didn't something
- // failed. Extract that job from the Compilation.
+/// Decide whether extra compiler frontend commands can be ignored.
+static bool ignoreExtraCC1Commands(const driver::Compilation *Compilation) {
const driver::JobList &Jobs = Compilation->getJobs();
const driver::ActionList &Actions = Compilation->getActions();
+
bool OffloadCompilation = false;
+
+ // Jobs and Actions look very
diff erent depending on whether the Clang tool
+ // injected -fsyntax-only or not. Try to handle both cases here.
+
+ for (const auto &Job : Jobs)
+ if (StringRef(Job.getExecutable()) == "clang-offload-bundler")
+ OffloadCompilation = true;
+
if (Jobs.size() > 1) {
for (auto A : Actions){
// On MacOSX real actions may end up being wrapped in BindArchAction
@@ -117,8 +121,33 @@ static const llvm::opt::ArgStringList *getCC1Arguments(
}
}
}
- if (Jobs.size() == 0 || !isa<driver::Command>(*Jobs.begin()) ||
- (Jobs.size() > 1 && !OffloadCompilation)) {
+
+ return OffloadCompilation;
+}
+
+namespace clang {
+namespace tooling {
+
+const llvm::opt::ArgStringList *
+getCC1Arguments(DiagnosticsEngine *Diagnostics,
+ driver::Compilation *Compilation) {
+ const driver::JobList &Jobs = Compilation->getJobs();
+
+ auto IsCC1Command = [](const driver::Command &Cmd) {
+ return StringRef(Cmd.getCreator().getName()) == "clang";
+ };
+
+ auto IsSrcFile = [](const driver::InputInfo &II) {
+ return isSrcFile(II.getType());
+ };
+
+ llvm::SmallVector<const driver::Command *, 1> CC1Jobs;
+ for (const driver::Command &Job : Jobs)
+ if (IsCC1Command(Job) && llvm::all_of(Job.getInputInfos(), IsSrcFile))
+ CC1Jobs.push_back(&Job);
+
+ if (CC1Jobs.empty() ||
+ (CC1Jobs.size() > 1 && !ignoreExtraCC1Commands(Compilation))) {
SmallString<256> error_msg;
llvm::raw_svector_ostream error_stream(error_msg);
Jobs.Print(error_stream, "; ", true);
@@ -127,19 +156,9 @@ static const llvm::opt::ArgStringList *getCC1Arguments(
return nullptr;
}
- // The one job we find should be to invoke clang again.
- const auto &Cmd = cast<driver::Command>(*Jobs.begin());
- if (StringRef(Cmd.getCreator().getName()) != "clang") {
- Diagnostics->Report(diag::err_fe_expected_clang_command);
- return nullptr;
- }
-
- return &Cmd.getArguments();
+ return &CC1Jobs[0]->getArguments();
}
-namespace clang {
-namespace tooling {
-
/// Returns a clang build invocation initialized from the CC1 flags.
CompilerInvocation *newInvocation(DiagnosticsEngine *Diagnostics,
const llvm::opt::ArgStringList &CC1Args,
diff --git a/clang/test/Tooling/clang-check-offload.cpp b/clang/test/Tooling/clang-check-offload.cpp
deleted file mode 100644
index 154bc043113e4..0000000000000
--- a/clang/test/Tooling/clang-check-offload.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: not clang-check "%s" -- -c -x hip -nogpulib 2>&1 | FileCheck %s
-
-// CHECK: C++ requires
-invalid;
diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp
index 313e8325c615b..fe85304860069 100644
--- a/clang/unittests/Tooling/ToolingTest.cpp
+++ b/clang/unittests/Tooling/ToolingTest.cpp
@@ -9,6 +9,8 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
@@ -18,6 +20,7 @@
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
@@ -258,6 +261,105 @@ TEST(ToolInvocation, DiagConsumerExpectingSourceManager) {
EXPECT_TRUE(Consumer.SawSourceManager);
}
+namespace {
+/// Overlays the real filesystem with the given VFS and returns the result.
+llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>
+overlayRealFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
+ auto RFS = llvm::vfs::getRealFileSystem();
+ auto OverlayFS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(RFS);
+ OverlayFS->pushOverlay(VFS);
+ return OverlayFS;
+}
+
+struct CommandLineExtractorTest : public ::testing::Test {
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFS;
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
+ driver::Driver Driver;
+
+public:
+ CommandLineExtractorTest()
+ : InMemoryFS(new llvm::vfs::InMemoryFileSystem),
+ Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)),
+ Driver("clang", llvm::sys::getDefaultTargetTriple(), *Diags,
+ "clang LLVM compiler", overlayRealFS(InMemoryFS)) {}
+
+ void addFile(StringRef Name, StringRef Content) {
+ InMemoryFS->addFile(Name, 0, llvm::MemoryBuffer::getMemBuffer(Content));
+ }
+
+ const llvm::opt::ArgStringList *
+ extractCC1Arguments(llvm::ArrayRef<const char *> Argv) {
+ const std::unique_ptr<driver::Compilation> Compilation(
+ Driver.BuildCompilation(llvm::makeArrayRef(Argv)));
+
+ return getCC1Arguments(Diags.get(), Compilation.get());
+ }
+};
+} // namespace
+
+TEST_F(CommandLineExtractorTest, AcceptOffloading) {
+ addFile("test.c", "int main() {}\n");
+ const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0",
+ "-x", "hip", "test.c",
+ "-nogpulib", "-nogpuinc"};
+ EXPECT_NE(extractCC1Arguments(Args), nullptr);
+}
+
+TEST_F(CommandLineExtractorTest, AcceptOffloadingCompile) {
+ addFile("test.c", "int main() {}\n");
+ const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0",
+ "-c", "-x", "hip",
+ "test.c", "-nogpulib", "-nogpuinc"};
+ EXPECT_NE(extractCC1Arguments(Args), nullptr);
+}
+
+TEST_F(CommandLineExtractorTest, AcceptOffloadingSyntaxOnly) {
+ addFile("test.c", "int main() {}\n");
+ const char *Args[] = {
+ "clang", "-target", "arm64-apple-macosx11.0.0",
+ "-fsyntax-only", "-x", "hip",
+ "test.c", "-nogpulib", "-nogpuinc"};
+ EXPECT_NE(extractCC1Arguments(Args), nullptr);
+}
+
+TEST_F(CommandLineExtractorTest, AcceptExternalAssembler) {
+ addFile("test.c", "int main() {}\n");
+ const char *Args[] = {
+ "clang", "-target", "arm64-apple-macosx11.0.0", "-fno-integrated-as",
+ "-c", "test.c"};
+ EXPECT_NE(extractCC1Arguments(Args), nullptr);
+}
+
+TEST_F(CommandLineExtractorTest, AcceptEmbedBitcode) {
+ addFile("test.c", "int main() {}\n");
+ const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0",
+ "-c", "-fembed-bitcode", "test.c"};
+ EXPECT_NE(extractCC1Arguments(Args), nullptr);
+}
+
+TEST_F(CommandLineExtractorTest, AcceptSaveTemps) {
+ addFile("test.c", "int main() {}\n");
+ const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0",
+ "-c", "-save-temps", "test.c"};
+ EXPECT_NE(extractCC1Arguments(Args), nullptr);
+}
+
+TEST_F(CommandLineExtractorTest, RejectMultipleArchitectures) {
+ addFile("test.c", "int main() {}\n");
+ const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0",
+ "-arch", "x86_64", "-arch",
+ "arm64", "-c", "test.c"};
+ EXPECT_EQ(extractCC1Arguments(Args), nullptr);
+}
+
+TEST_F(CommandLineExtractorTest, RejectMultipleInputFiles) {
+ addFile("one.c", "void one() {}\n");
+ addFile("two.c", "void two() {}\n");
+ const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0",
+ "-c", "one.c", "two.c"};
+ EXPECT_EQ(extractCC1Arguments(Args), nullptr);
+}
+
struct VerifyEndCallback : public SourceFileCallbacks {
VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
bool handleBeginSource(CompilerInstance &CI) override {
More information about the cfe-commits
mailing list