From af34d35d72d273699e5d9ee7923edc17dc950791 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 | 19 +++++++++-- clang/unittests/libclang/DriverTest.cpp | 43 +++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/clang/tools/libclang/Driver.cpp b/clang/tools/libclang/Driver.cpp index 4a1d4c516ee8c..5a64b5d90cf35 100644 --- a/clang/tools/libclang/Driver.cpp +++ b/clang/tools/libclang/Driver.cpp @@ -41,7 +41,22 @@ clang_Driver_getExternalActionsForCommand_v0(int ArgC, const char **ArgV, return nullptr; CXDiagnosticSetDiagnosticConsumer DiagConsumer; - auto DiagOpts = CreateAndPopulateDiagOpts(ArrayRef(ArgV, ArgC)); + + 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(&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(DiagOpts.release(), &DiagConsumer, false); @@ -64,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); +}