From 88f3fb127ec4535119788b4c4adadc60248cf37c Mon Sep 17 00:00:00 2001 From: Callie Wakamo Date: Sat, 12 Apr 2025 17:13:56 -0700 Subject: [PATCH] Added support for expanding response files in clang_Driver_getExternalActionsForCommand_v0. This is necessary because build systems like SwiftBuild may pass arguments to the Clang driver via response files. Without this, the response files are treated as inputs and passed along to the external actions themselves, which is incorrect. This resolves swiftlang#10441. --- clang/tools/libclang/Driver.cpp | 22 ++++++++++--- clang/unittests/libclang/DriverTest.cpp | 43 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/clang/tools/libclang/Driver.cpp b/clang/tools/libclang/Driver.cpp index d479bba2e28ff..4d7fbdb8af849 100644 --- a/clang/tools/libclang/Driver.cpp +++ b/clang/tools/libclang/Driver.cpp @@ -40,15 +40,29 @@ clang_Driver_getExternalActionsForCommand_v0(int ArgC, const char **ArgV, if (ArgC < 1) return nullptr; - CXDiagnosticSetDiagnosticConsumer DiagConsumer; - auto DiagOpts = CreateAndPopulateDiagOpts(ArrayRef(ArgV, ArgC)); - // Use createPhysicalFileSystem instead of getRealFileSystem so that // setCurrentWorkingDirectory doesn't change the working directory of the // process. std::unique_ptr VFS = llvm::vfs::createPhysicalFileSystem(); + CXDiagnosticSetDiagnosticConsumer DiagConsumer; + + SmallVector Args(ArgV, ArgV + ArgC); + llvm::BumpPtrAllocator Alloc; + if (llvm::Error E = + driver::expandResponseFiles(Args, /*CLMode=*/false, Alloc)) { + // Construct a default DiagnosticOptions to use to emit the failure. + DiagnosticOptions DiagOpts; + auto Diags = CompilerInstance::createDiagnostics(*VFS, &DiagOpts, + &DiagConsumer, false); + + Diags->Report(diag::err_drv_expand_response_file) + << llvm::toString(std::move(E)); + return nullptr; + } + + auto DiagOpts = CreateAndPopulateDiagOpts(Args); auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts.release(), &DiagConsumer, false); if (WorkingDirectory) @@ -65,7 +79,7 @@ clang_Driver_getExternalActionsForCommand_v0(int ArgC, const char **ArgV, VFS.release()); TheDriver.setCheckInputsExist(false); std::unique_ptr C( - TheDriver.BuildCompilation(ArrayRef(ArgV, ArgC))); + TheDriver.BuildCompilation(Args)); if (!C || Diags->hasErrorOccurred()) { if (OutDiags) *OutDiags = DiagConsumer.getDiagnosticSet(); diff --git a/clang/unittests/libclang/DriverTest.cpp b/clang/unittests/libclang/DriverTest.cpp index 03d435904784f..e39fa0519eab3 100644 --- a/clang/unittests/libclang/DriverTest.cpp +++ b/clang/unittests/libclang/DriverTest.cpp @@ -11,6 +11,8 @@ #include "llvm/Support/Debug.h" #include "gtest/gtest.h" +#include "TestUtils.h" + #define DEBUG_TYPE "driver-test" TEST(DriverTests, Basic) { @@ -129,3 +131,44 @@ TEST(DriverTests, DriverParsesDiagnosticsOptions) { clang_disposeDiagnosticSet(Diags); clang_Driver_ExternalActionList_dispose(EAL); } + +class LibclangDriverResponseFileTest : public LibclangParseTest {}; + +TEST_F(LibclangDriverResponseFileTest, DriverResponseFile) { + // Enable -Weverything (a flag not set by default) via a response file. + std::string ResponseFilename = "AdditionalOptions.resp"; + WriteFile(ResponseFilename, "-Weverything\n"); + + llvm::SmallString<256> ResponseArg("@"); + ResponseArg.append(ResponseFilename); + + const char *ArgV[] = {"clang", + ResponseArg.c_str(), + "-c", + "t.cpp", + "-o", + "t.o"}; + + CXDiagnosticSet Diags; + CXExternalActionList *EAL = clang_Driver_getExternalActionsForCommand_v0( + std::extent_v, ArgV, nullptr, "/", &Diags); + + ASSERT_NE(EAL, nullptr); + ASSERT_EQ(EAL->Count, 1); + ASSERT_EQ(nullptr, Diags); + + auto *CompileAction = EAL->Actions[0]; + ASSERT_GE(CompileAction->ArgC, 2); + EXPECT_STREQ(CompileAction->ArgV[0], "clang"); + EXPECT_STREQ(CompileAction->ArgV[1], "-cc1"); + + const char **WFlag = std::find(CompileAction->ArgV, + CompileAction->ArgV + CompileAction->ArgC, + llvm::StringRef("-Weverything")); + + ASSERT_NE(WFlag, CompileAction->ArgV + CompileAction->ArgC); + EXPECT_STREQ(*WFlag, "-Weverything"); + + clang_disposeDiagnosticSet(Diags); + clang_Driver_ExternalActionList_dispose(EAL); +}