https://github.com/Meinersbur updated https://github.com/llvm/llvm-project/pull/225678
>From ee4cebf43ee6d8a351534c5812e92256a9d530ed Mon Sep 17 00:00:00 2001 From: Michael Kruse <[email protected]> Date: Tue, 22 Sep 2026 18:48:29 +0200 Subject: [PATCH 1/4] Reapply "[Clang][Driver] Final phase also determined by input (#218802)" (#225416) This reverts commit 976c919fbc123e7fd7058223c23ad9c312477b4b. --- clang/include/clang/Driver/Driver.h | 1 + clang/include/clang/Driver/Types.h | 6 ++-- clang/lib/Driver/Driver.cpp | 51 ++++++++++++++++++++++------- clang/lib/Driver/Types.cpp | 5 +-- clang/test/Driver/Inputs/object0.o | 0 clang/test/Driver/aix-ld.c | 2 +- clang/test/Driver/pch-inputs.h | 48 +++++++++++++++++++++++++++ 7 files changed, 95 insertions(+), 18 deletions(-) create mode 100644 clang/test/Driver/Inputs/object0.o create mode 100644 clang/test/Driver/pch-inputs.h diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 15b6fdcb8a5746..e653d8e3a2dbe6 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -339,6 +339,7 @@ class Driver { // modes. Fold this functionality into Types::getCompilationPhases and // handleArguments. phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL, + llvm::ArrayRef<InputTy>, llvm::opt::Arg **FinalPhaseArg = nullptr) const; llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> diff --git a/clang/include/clang/Driver/Types.h b/clang/include/clang/Driver/Types.h index 9dd89e1904a4f0..9ec456773716dd 100644 --- a/clang/include/clang/Driver/Types.h +++ b/clang/include/clang/Driver/Types.h @@ -115,9 +115,9 @@ namespace types { /// done for type 'Id' up until including LastPhase. llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> getCompilationPhases(ID Id, phases::ID LastPhase = phases::IfsMerge); - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> - getCompilationPhases(const clang::driver::Driver &Driver, - llvm::opt::DerivedArgList &DAL, ID Id); + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> getCompilationPhases( + const clang::driver::Driver &Driver, llvm::opt::DerivedArgList &DAL, + llvm::ArrayRef<std::pair<ID, const llvm::opt::Arg *>> Inputs, ID Id); /// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given /// C type (used for clang++ emulation of g++ behaviour) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 7649941a68b1cc..7a742e404bf5ca 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -352,8 +352,10 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, // Determine which compilation mode we are in. We look for options which // affect the phase, starting with the earliest phases, and record which -// option we used to determine the final phase. +// option we used to determine the final phase. In absence of any explicit +// action command line option, derive the compilation mode from the inputs. phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, + llvm::ArrayRef<InputTy> Inputs, Arg **FinalPhaseArg) const { Arg *PhaseArg = nullptr; phases::ID FinalPhase; @@ -401,9 +403,33 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, } else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_interface_stubs))) { FinalPhase = phases::IfsMerge; - // Otherwise do everything. - } else - FinalPhase = phases::Link; + // Otherwise autodetect from last phase triggered by input file. + } else { + FinalPhase = phases::Preprocess; + bool AnyPhase = false; + for (auto &I : Inputs) { + types::ID InputType = I.first; + const Arg *InputArg = I.second; + + // Linker options should not trigger more phases. + if (InputArg->getOption().hasFlag(options::LinkerInput)) + continue; + + // Relies on the compilation phases being ordered. + auto PL = types::getCompilationPhases(InputType); + if (PL.empty()) + continue; + + phases::ID LastPL = PL.back(); + if (LastPL > FinalPhase) + FinalPhase = LastPL; + AnyPhase = true; + } + + // Fall back to "do everything" when consistency check fails. + if (!AnyPhase || FinalPhase > phases::Link) + FinalPhase = phases::Link; + } if (FinalPhaseArg) *FinalPhaseArg = PhaseArg; @@ -1849,7 +1875,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs); if (HasConfigFileTail && Inputs.size()) { Arg *FinalPhaseArg; - if (getFinalPhase(*TranslatedArgs, &FinalPhaseArg) == phases::Link) { + if (getFinalPhase(*TranslatedArgs, Inputs, &FinalPhaseArg) == + phases::Link) { DerivedArgList TranslatedLinkerIns(*CfgOptionsTail); for (Arg *A : *CfgOptionsTail) TranslatedLinkerIns.append(A); @@ -3434,7 +3461,7 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, } Arg *FinalPhaseArg; - phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg); + phases::ID FinalPhase = getFinalPhase(Args, Inputs, &FinalPhaseArg); if (FinalPhase == phases::Link) { if (Args.hasArgNoClaim(options::OPT_hipstdpar)) { @@ -3531,8 +3558,8 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, else Diag(clang::diag::warn_drv_input_file_unused) << InputArg->getAsString(Args) << getPhaseName(InitialPhase) - << !!FinalPhaseArg - << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : ""); + << !FinalPhaseArg + << (FinalPhaseArg ? FinalPhaseArg->getSpelling() : ""); continue; } @@ -3613,7 +3640,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, C.isOffloadingHostKind(Action::OFK_HIP) && offloadDeviceOnly() && Args.hasArg(options::OPT_hip_link) && Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false) && - getFinalPhase(Args) == phases::Link && + getFinalPhase(Args, Inputs) == phases::Link && !Args.hasArg(options::OPT_emit_llvm) && Args.hasFlag(options::OPT_gpu_bundle_output, options::OPT_no_gpu_bundle_output, true); @@ -3627,7 +3654,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, types::ID InputType = I.first; const Arg *InputArg = I.second; - auto PL = types::getCompilationPhases(*this, Args, InputType); + auto PL = types::getCompilationPhases(*this, Args, Inputs, InputType); if (PL.empty()) continue; @@ -4125,7 +4152,7 @@ Driver::BuildOffloadingActions(Compilation &C, llvm::opt::DerivedArgList &Args, // Don't build offloading actions if we do not have a compile action. If // preprocessing only ignore embedding. if (!(isa<CompileJobAction>(HostAction) || - getFinalPhase(Args) == phases::Preprocess)) + getFinalPhase(Args, {Input}) == phases::Preprocess)) return HostAction; bool UsesLLVMOffloading = Args.hasArg( @@ -4178,7 +4205,7 @@ Driver::BuildOffloadingActions(Compilation &C, llvm::opt::DerivedArgList &Args, .isOSDarwin()) HostAction->setCannotBeCollapsedWithNextDependentAction(); - auto PL = types::getCompilationPhases(*this, Args, InputType); + auto PL = types::getCompilationPhases(*this, Args, {Input}, InputType); for (phases::ID Phase : PL) { if (Phase == phases::Link) { diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index 4cca8acd515d7b..618fb402af7284 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -429,8 +429,9 @@ types::getCompilationPhases(ID Id, phases::ID LastPhase) { llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> types::getCompilationPhases(const clang::driver::Driver &Driver, - llvm::opt::DerivedArgList &DAL, ID Id) { - return types::getCompilationPhases(Id, Driver.getFinalPhase(DAL)); + llvm::opt::DerivedArgList &DAL, + llvm::ArrayRef<InputTy> Inputs, ID Id) { + return types::getCompilationPhases(Id, Driver.getFinalPhase(DAL, Inputs)); } ID types::lookupCXXTypeForCType(ID Id) { diff --git a/clang/test/Driver/Inputs/object0.o b/clang/test/Driver/Inputs/object0.o new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/clang/test/Driver/aix-ld.c b/clang/test/Driver/aix-ld.c index bedd224eeca9ce..641908afc8d986 100644 --- a/clang/test/Driver/aix-ld.c +++ b/clang/test/Driver/aix-ld.c @@ -1171,4 +1171,4 @@ // RUN: -K \ // RUN: -c \ // RUN: | FileCheck --check-prefixes=CHECK-K-UNUSED %s -// CHECK-K-UNUSED: clang: warning: -K: 'linker' input unused [-Wunused-command-line-argument] +// CHECK-K-UNUSED: clang: warning: -K: 'linker' input unused when '-c' is present [-Wunused-command-line-argument] diff --git a/clang/test/Driver/pch-inputs.h b/clang/test/Driver/pch-inputs.h new file mode 100644 index 00000000000000..fa6f94f996915f --- /dev/null +++ b/clang/test/Driver/pch-inputs.h @@ -0,0 +1,48 @@ +// RUN: rm -rf %t +// RUN: mkdir %t + +// Warn about linker options being ignored when not linking +// RUN: %clang %s -lfoo -o %t/tmp1.pch -### 2>&1 | FileCheck %s --check-prefix=UNUSED-L,SINGLEHEADER +// RUN: %clang %s -x c++-header -lfoo -o %t/tmp1.pch -### 2>&1 | FileCheck %s --check-prefix=UNUSED-L,SINGLEHEADER +// UNUSED-L: clang: warning: -lfoo: 'linker' input unused [-Wunused-command-line-argument] + +// RUN: %clang %s -Wl,--whole-archive -o %t/tmp1.pch -### 2>&1 | FileCheck %s --check-prefix=UNUSED-WL,SINGLEHEADER +// UNUSED-WL: clang: warning: -Wl,--whole-archive: 'linker' input unused [-Wunused-command-line-argument] + +// RUN: %clang %S/Inputs/header1.h %S/Inputs/header2.h -lfoo -### 2>&1 | FileCheck %s --check-prefix=UNUSED-L,MULTIHEADER + + +// Error with single -o when there are multiple output files +// RUN: not %clang %S/Inputs/header1.h %S/Inputs/header2.h -lfoo -o %t/tmp2.pch -### 2>&1 | FileCheck %s --check-prefix=UNUSED-L,MULTIOUTPUT +// MULTIOUTPUT: clang: error: cannot specify -o when generating multiple output files + +// An actual linker input file (object0.o) triggers an error, not a warning +// RUN: not %clang %s %S/Inputs/object0.o -o %t/tmp3.pch -### 2>&1 | FileCheck %s --check-prefix=MULTIOUTPUT + +// Other input types that do not link +// RUN: %clang -x cl-header %s -Xlinker -somelinkerflag -### 2>&1 | FileCheck %s --check-prefix=UNUSED-XLINKER +// RUN: %clang -x objective-c++-header %s -Xlinker -somelinkerflag -### 2>&1 | FileCheck %s --check-prefix=UNUSED-XLINKER +// RUN: %clang -x hlsl %s -Xlinker -somelinkerflag -### 2>&1 | FileCheck %s --check-prefix=UNUSED-XLINKER +// UNUSED-XLINKER: clang: warning: -Xlinker -somelinkerflag: 'linker' input unused [-Wunused-command-line-argument] + + +// Normal case: Single header file input compiles to .pch even without --precompile +// RUN: %clang %s -o %t/tmp1.pch -### 2>&1 | FileCheck %s --check-prefix=SINGLEHEADER +// SINGLEHEADER: "-cc1" +// SINGLEHEADER: "-emit-pch" +// SINGLEHEADER: "-o" +// SINGLEHEADER: tmp1.pch" + + +// Multiple header files input compiles to one .pch each even without --precompile +// RUN: %clang %S/Inputs/header1.h %S/Inputs/header2.h -### 2>&1 | FileCheck %s --check-prefix=MULTIHEADER +// MULTIHEADER: "-cc1" +// MULTIHEADER: "-emit-pch" +// MULTIHEADER: "-o" +// MULTIHEADER: header1.h.pch" +// MULTIHEADER: "-cc1" +// MULTIHEADER: "-emit-pch" +// MULTIHEADER: "-o" +// MULTIHEADER: header2.h.pch" + + >From f6e7d49caa85f136de08e75f33366057b62b49b2 Mon Sep 17 00:00:00 2001 From: Michael Kruse <[email protected]> Date: Wed, 23 Sep 2026 11:23:41 +0200 Subject: [PATCH 2/4] Prototype --- clang/include/clang/Driver/Compilation.h | 6 ++++ clang/include/clang/Driver/Driver.h | 4 +-- clang/include/clang/Driver/Types.h | 2 +- clang/lib/Driver/Driver.cpp | 36 ++++++++++++------------ clang/lib/Driver/Types.cpp | 4 +-- 5 files changed, 29 insertions(+), 23 deletions(-) diff --git a/clang/include/clang/Driver/Compilation.h b/clang/include/clang/Driver/Compilation.h index 825806b6cfe332..55cfdeddc39398 100644 --- a/clang/include/clang/Driver/Compilation.h +++ b/clang/include/clang/Driver/Compilation.h @@ -13,6 +13,7 @@ #include "clang/Basic/OffloadArch.h" #include "clang/Driver/Action.h" #include "clang/Driver/Job.h" +#include "clang/Driver/Phases.h" #include "clang/Driver/Util.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -64,6 +65,11 @@ class Compilation { /// The original (untranslated) input argument list. llvm::opt::InputArgList *Args; + public: + phases::ID FinalPhase; + llvm::opt:: Arg *FinalPhaseArg; + private: + /// The driver translated arguments. Note that toolchains may perform their /// own argument translation. llvm::opt::DerivedArgList *TranslatedArgs; diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index e653d8e3a2dbe6..eebedc985f23ce 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -338,9 +338,9 @@ class Driver { // TODO: Much of what getFinalPhase returns are not actually true compiler // modes. Fold this functionality into Types::getCompilationPhases and // handleArguments. - phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL, + phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL, llvm::ArrayRef<InputTy>, - llvm::opt::Arg **FinalPhaseArg = nullptr) const; + llvm::opt::Arg **FinalPhaseArg = nullptr) const ; llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> executeProgram(llvm::ArrayRef<llvm::StringRef> Args) const; diff --git a/clang/include/clang/Driver/Types.h b/clang/include/clang/Driver/Types.h index 9ec456773716dd..f192a773a493a6 100644 --- a/clang/include/clang/Driver/Types.h +++ b/clang/include/clang/Driver/Types.h @@ -117,7 +117,7 @@ namespace types { getCompilationPhases(ID Id, phases::ID LastPhase = phases::IfsMerge); llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> getCompilationPhases( const clang::driver::Driver &Driver, llvm::opt::DerivedArgList &DAL, - llvm::ArrayRef<std::pair<ID, const llvm::opt::Arg *>> Inputs, ID Id); + llvm::ArrayRef<std::pair<ID, const llvm::opt::Arg *>> Inputs, ID Id, phases::ID FinalPhase); /// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given /// C type (used for clang++ emulation of g++ behaviour) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 7a742e404bf5ca..fce60d25667870 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1873,9 +1873,10 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // Construct the list of inputs. InputList Inputs; BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs); - if (HasConfigFileTail && Inputs.size()) { - Arg *FinalPhaseArg; - if (getFinalPhase(*TranslatedArgs, Inputs, &FinalPhaseArg) == + C->FinalPhase = getFinalPhase(*TranslatedArgs, Inputs, &C->FinalPhaseArg) ; + auto FinalPhase = C->FinalPhase; + if (HasConfigFileTail && Inputs.size()) { + if (FinalPhase== phases::Link) { DerivedArgList TranslatedLinkerIns(*CfgOptionsTail); for (Arg *A : *CfgOptionsTail) @@ -3460,10 +3461,9 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, YcArg = nullptr; } - Arg *FinalPhaseArg; - phases::ID FinalPhase = getFinalPhase(Args, Inputs, &FinalPhaseArg); - if (FinalPhase == phases::Link) { + + if (C.FinalPhase == phases::Link) { if (Args.hasArgNoClaim(options::OPT_hipstdpar)) { Args.AddFlagArg(nullptr, getOpts().getOption(options::OPT_hip_link)); Args.AddFlagArg(nullptr, @@ -3498,7 +3498,7 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, } } - if (FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) { + if (C.FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) { // If only preprocessing or /Y- is used, all pch handling is disabled. // Rather than check for it everywhere, just remove clang-cl pch-related // flags here. @@ -3516,7 +3516,7 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, Args.eraseArg(options::OPT_include_pch); } - bool LinkOnly = phases::Link == FinalPhase && Inputs.size() > 0; + bool LinkOnly = phases::Link == C.FinalPhase && Inputs.size() > 0; for (auto &I : Inputs) { types::ID InputType = I.first; const Arg *InputArg = I.second; @@ -3528,7 +3528,7 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, // If the first step comes after the final phase we are doing as part of // this compilation, warn the user about it. - if (InitialPhase > FinalPhase) { + if (InitialPhase > C.FinalPhase) { if (InputArg->isClaimed()) continue; @@ -3553,19 +3553,19 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, Args.getLastArg(options::OPT_M, options::OPT_MM)) && getPreprocessedType(InputType) == types::TY_INVALID) Diag(clang::diag::warn_drv_preprocessed_input_file_unused) - << InputArg->getAsString(Args) << !!FinalPhaseArg - << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : ""); + << InputArg->getAsString(Args) << !!C.FinalPhaseArg + << (C.FinalPhaseArg ? C.FinalPhaseArg->getOption().getName() : ""); else Diag(clang::diag::warn_drv_input_file_unused) << InputArg->getAsString(Args) << getPhaseName(InitialPhase) - << !FinalPhaseArg - << (FinalPhaseArg ? FinalPhaseArg->getSpelling() : ""); + << !C.FinalPhaseArg + << (C.FinalPhaseArg ? C.FinalPhaseArg->getSpelling() : ""); continue; } if (YcArg) { // Add a separate precompile phase for the compile phase. - if (FinalPhase >= phases::Compile) { + if (C.FinalPhase >= phases::Compile) { const types::ID HeaderType = lookupHeaderTypeForSourceType(InputType); // Build the pipeline for the pch file. Action *ClangClPch = C.MakeAction<InputAction>(*InputArg, HeaderType); @@ -3640,7 +3640,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, C.isOffloadingHostKind(Action::OFK_HIP) && offloadDeviceOnly() && Args.hasArg(options::OPT_hip_link) && Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false) && - getFinalPhase(Args, Inputs) == phases::Link && + C.FinalPhase == phases::Link && !Args.hasArg(options::OPT_emit_llvm) && Args.hasFlag(options::OPT_gpu_bundle_output, options::OPT_no_gpu_bundle_output, true); @@ -3654,7 +3654,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, types::ID InputType = I.first; const Arg *InputArg = I.second; - auto PL = types::getCompilationPhases(*this, Args, Inputs, InputType); + auto PL = types::getCompilationPhases(*this, Args, Inputs, InputType, C.FinalPhase); if (PL.empty()) continue; @@ -4152,7 +4152,7 @@ Driver::BuildOffloadingActions(Compilation &C, llvm::opt::DerivedArgList &Args, // Don't build offloading actions if we do not have a compile action. If // preprocessing only ignore embedding. if (!(isa<CompileJobAction>(HostAction) || - getFinalPhase(Args, {Input}) == phases::Preprocess)) + C.FinalPhase == phases::Preprocess)) return HostAction; bool UsesLLVMOffloading = Args.hasArg( @@ -4205,7 +4205,7 @@ Driver::BuildOffloadingActions(Compilation &C, llvm::opt::DerivedArgList &Args, .isOSDarwin()) HostAction->setCannotBeCollapsedWithNextDependentAction(); - auto PL = types::getCompilationPhases(*this, Args, {Input}, InputType); + auto PL = types::getCompilationPhases(*this, Args, {Input}, InputType, C.FinalPhase); for (phases::ID Phase : PL) { if (Phase == phases::Link) { diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index 618fb402af7284..11292d9240877a 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -430,8 +430,8 @@ types::getCompilationPhases(ID Id, phases::ID LastPhase) { llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> types::getCompilationPhases(const clang::driver::Driver &Driver, llvm::opt::DerivedArgList &DAL, - llvm::ArrayRef<InputTy> Inputs, ID Id) { - return types::getCompilationPhases(Id, Driver.getFinalPhase(DAL, Inputs)); + llvm::ArrayRef<InputTy> Inputs, ID Id, phases::ID FinalPhase) { + return types::getCompilationPhases(Id, FinalPhase); } ID types::lookupCXXTypeForCType(ID Id) { >From f11061c51e0e7e011612fb1195e377ca2acda8ec Mon Sep 17 00:00:00 2001 From: Michael Kruse <[email protected]> Date: Wed, 23 Sep 2026 12:26:09 +0200 Subject: [PATCH 3/4] Fix fix O(n^2) regression --- clang/include/clang/Driver/Compilation.h | 21 +++++++--- clang/include/clang/Driver/Driver.h | 10 +++-- clang/include/clang/Driver/Types.h | 3 +- clang/lib/Driver/Driver.cpp | 53 +++++++++++++++--------- clang/lib/Driver/Types.cpp | 3 +- clang/test/Driver/aix-ld.c | 2 +- clang/test/Driver/pch-inputs.h | 8 ++-- 7 files changed, 64 insertions(+), 36 deletions(-) diff --git a/clang/include/clang/Driver/Compilation.h b/clang/include/clang/Driver/Compilation.h index 55cfdeddc39398..f98fc66b6cb1b3 100644 --- a/clang/include/clang/Driver/Compilation.h +++ b/clang/include/clang/Driver/Compilation.h @@ -65,15 +65,17 @@ class Compilation { /// The original (untranslated) input argument list. llvm::opt::InputArgList *Args; - public: - phases::ID FinalPhase; - llvm::opt:: Arg *FinalPhaseArg; - private: - /// The driver translated arguments. Note that toolchains may perform their /// own argument translation. llvm::opt::DerivedArgList *TranslatedArgs; + /// Which compilation phase is supposed to be the last job. + phases::ID FinalPhase; + + /// Which compiler argument determined what the \p FinalPhase should be (used + /// for diagnostics). + llvm::opt::Arg *FinalPhaseArg = nullptr; + /// The list of actions we've created via MakeAction. This is not accessible /// to consumers; it's here just to manage ownership. std::vector<std::unique_ptr<Action>> AllActions; @@ -207,6 +209,15 @@ class Compilation { llvm::opt::DerivedArgList &getArgs() { return *TranslatedArgs; } + void setFinalPhase(phases::ID FinalPhase, llvm::opt::Arg *FinalPhaseArg) { + this->FinalPhase = FinalPhase; + this->FinalPhaseArg = FinalPhaseArg; + } + + phases::ID getFinalPhase() const { return FinalPhase; } + + llvm::opt::Arg *getFinalPhaseArg() const { return FinalPhaseArg; } + ActionList &getActions() { return Actions; } const ActionList &getActions() const { return Actions; } diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index eebedc985f23ce..fa4eef66e3dea3 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -332,16 +332,20 @@ class Driver { LLVM_PREFERRED_TYPE(bool) unsigned ProbePrecompiled : 1; -public: // getFinalPhase - Determine which compilation mode we are in and record // which option we used to determine the final phase. // TODO: Much of what getFinalPhase returns are not actually true compiler // modes. Fold this functionality into Types::getCompilationPhases and // handleArguments. - phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL, + phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL, llvm::ArrayRef<InputTy>, - llvm::opt::Arg **FinalPhaseArg = nullptr) const ; + llvm::opt::Arg **FinalPhaseArg = nullptr) const; + + /// Set the final phase in \p C based on compiler arguments, driver state, and + /// the \p Inputs to be processed. + void updateFinalPhase(Compilation &C, llvm::ArrayRef<InputTy> Inputs) const; +public: llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> executeProgram(llvm::ArrayRef<llvm::StringRef> Args) const; diff --git a/clang/include/clang/Driver/Types.h b/clang/include/clang/Driver/Types.h index f192a773a493a6..e4f3536ed1c6ea 100644 --- a/clang/include/clang/Driver/Types.h +++ b/clang/include/clang/Driver/Types.h @@ -117,7 +117,8 @@ namespace types { getCompilationPhases(ID Id, phases::ID LastPhase = phases::IfsMerge); llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> getCompilationPhases( const clang::driver::Driver &Driver, llvm::opt::DerivedArgList &DAL, - llvm::ArrayRef<std::pair<ID, const llvm::opt::Arg *>> Inputs, ID Id, phases::ID FinalPhase); + llvm::ArrayRef<std::pair<ID, const llvm::opt::Arg *>> Inputs, ID Id, + phases::ID FinalPhase); /// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given /// C type (used for clang++ emulation of g++ behaviour) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index fce60d25667870..8f3d4f803810f7 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -437,6 +437,13 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, return FinalPhase; } +void Driver::updateFinalPhase(Compilation &C, + llvm::ArrayRef<InputTy> Inputs) const { + Arg *FinalPhaseArg = nullptr; + phases ::ID FinalPhase = getFinalPhase(C.getArgs(), Inputs, &FinalPhaseArg); + C.setFinalPhase(FinalPhase, FinalPhaseArg); +} + llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> Driver::executeProgram(llvm::ArrayRef<llvm::StringRef> Args) const { llvm::SmallString<64> OutputFile; @@ -1873,15 +1880,17 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // Construct the list of inputs. InputList Inputs; BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs); - C->FinalPhase = getFinalPhase(*TranslatedArgs, Inputs, &C->FinalPhaseArg) ; - auto FinalPhase = C->FinalPhase; - if (HasConfigFileTail && Inputs.size()) { - if (FinalPhase== - phases::Link) { + updateFinalPhase(*C, Inputs); + phases::ID FinalPhase = C->getFinalPhase(); + + if (HasConfigFileTail && Inputs.size()) { + if (FinalPhase == phases::Link) { DerivedArgList TranslatedLinkerIns(*CfgOptionsTail); for (Arg *A : *CfgOptionsTail) TranslatedLinkerIns.append(A); BuildInputs(C->getDefaultToolChain(), TranslatedLinkerIns, Inputs); + updateFinalPhase(*C, Inputs); + FinalPhase = C->getFinalPhase(); } } @@ -2149,6 +2158,7 @@ void Driver::generateCompilationDiagnostics( // Construct the list of inputs. InputList Inputs; BuildInputs(C.getDefaultToolChain(), C.getArgs(), Inputs); + updateFinalPhase(C, Inputs); ArgStringList IRInputs; for (InputList::iterator it = Inputs.begin(), ie = Inputs.end(); it != ie;) { @@ -3461,9 +3471,10 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, YcArg = nullptr; } + phases::ID FinalPhase = C.getFinalPhase(); + llvm::opt::Arg *FinalPhaseArg = C.getFinalPhaseArg(); - - if (C.FinalPhase == phases::Link) { + if (FinalPhase == phases::Link) { if (Args.hasArgNoClaim(options::OPT_hipstdpar)) { Args.AddFlagArg(nullptr, getOpts().getOption(options::OPT_hip_link)); Args.AddFlagArg(nullptr, @@ -3498,7 +3509,7 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, } } - if (C.FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) { + if (FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) { // If only preprocessing or /Y- is used, all pch handling is disabled. // Rather than check for it everywhere, just remove clang-cl pch-related // flags here. @@ -3516,7 +3527,7 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, Args.eraseArg(options::OPT_include_pch); } - bool LinkOnly = phases::Link == C.FinalPhase && Inputs.size() > 0; + bool LinkOnly = phases::Link == FinalPhase && Inputs.size() > 0; for (auto &I : Inputs) { types::ID InputType = I.first; const Arg *InputArg = I.second; @@ -3528,7 +3539,7 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, // If the first step comes after the final phase we are doing as part of // this compilation, warn the user about it. - if (InitialPhase > C.FinalPhase) { + if (InitialPhase > FinalPhase) { if (InputArg->isClaimed()) continue; @@ -3553,19 +3564,19 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, Args.getLastArg(options::OPT_M, options::OPT_MM)) && getPreprocessedType(InputType) == types::TY_INVALID) Diag(clang::diag::warn_drv_preprocessed_input_file_unused) - << InputArg->getAsString(Args) << !!C.FinalPhaseArg - << (C.FinalPhaseArg ? C.FinalPhaseArg->getOption().getName() : ""); + << InputArg->getAsString(Args) << !!FinalPhaseArg + << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : ""); else Diag(clang::diag::warn_drv_input_file_unused) << InputArg->getAsString(Args) << getPhaseName(InitialPhase) - << !C.FinalPhaseArg - << (C.FinalPhaseArg ? C.FinalPhaseArg->getSpelling() : ""); + << !!FinalPhaseArg + << (FinalPhaseArg ? FinalPhaseArg->getSpelling() : ""); continue; } if (YcArg) { // Add a separate precompile phase for the compile phase. - if (C.FinalPhase >= phases::Compile) { + if (FinalPhase >= phases::Compile) { const types::ID HeaderType = lookupHeaderTypeForSourceType(InputType); // Build the pipeline for the pch file. Action *ClangClPch = C.MakeAction<InputAction>(*InputArg, HeaderType); @@ -3636,12 +3647,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Args.ClaimAllArgs(options::OPT_no_offload_new_driver); Args.ClaimAllArgs(options::OPT_offload_new_driver); + phases::ID FinalPhase = C.getFinalPhase(); bool HIPRDCDeviceOnlyFatBin = C.isOffloadingHostKind(Action::OFK_HIP) && offloadDeviceOnly() && Args.hasArg(options::OPT_hip_link) && Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false) && - C.FinalPhase == phases::Link && - !Args.hasArg(options::OPT_emit_llvm) && + FinalPhase == phases::Link && !Args.hasArg(options::OPT_emit_llvm) && Args.hasFlag(options::OPT_gpu_bundle_output, options::OPT_no_gpu_bundle_output, true); @@ -3654,7 +3665,8 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, types::ID InputType = I.first; const Arg *InputArg = I.second; - auto PL = types::getCompilationPhases(*this, Args, Inputs, InputType, C.FinalPhase); + auto PL = + types::getCompilationPhases(*this, Args, Inputs, InputType, FinalPhase); if (PL.empty()) continue; @@ -4152,7 +4164,7 @@ Driver::BuildOffloadingActions(Compilation &C, llvm::opt::DerivedArgList &Args, // Don't build offloading actions if we do not have a compile action. If // preprocessing only ignore embedding. if (!(isa<CompileJobAction>(HostAction) || - C.FinalPhase == phases::Preprocess)) + C.getFinalPhase() == phases::Preprocess)) return HostAction; bool UsesLLVMOffloading = Args.hasArg( @@ -4205,7 +4217,8 @@ Driver::BuildOffloadingActions(Compilation &C, llvm::opt::DerivedArgList &Args, .isOSDarwin()) HostAction->setCannotBeCollapsedWithNextDependentAction(); - auto PL = types::getCompilationPhases(*this, Args, {Input}, InputType, C.FinalPhase); + auto PL = types::getCompilationPhases(*this, Args, {Input}, InputType, + C.getFinalPhase()); for (phases::ID Phase : PL) { if (Phase == phases::Link) { diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index 11292d9240877a..e04d3c9a05ace3 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -430,7 +430,8 @@ types::getCompilationPhases(ID Id, phases::ID LastPhase) { llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> types::getCompilationPhases(const clang::driver::Driver &Driver, llvm::opt::DerivedArgList &DAL, - llvm::ArrayRef<InputTy> Inputs, ID Id, phases::ID FinalPhase) { + llvm::ArrayRef<InputTy> Inputs, ID Id, + phases::ID FinalPhase) { return types::getCompilationPhases(Id, FinalPhase); } diff --git a/clang/test/Driver/aix-ld.c b/clang/test/Driver/aix-ld.c index 641908afc8d986..bedd224eeca9ce 100644 --- a/clang/test/Driver/aix-ld.c +++ b/clang/test/Driver/aix-ld.c @@ -1171,4 +1171,4 @@ // RUN: -K \ // RUN: -c \ // RUN: | FileCheck --check-prefixes=CHECK-K-UNUSED %s -// CHECK-K-UNUSED: clang: warning: -K: 'linker' input unused when '-c' is present [-Wunused-command-line-argument] +// CHECK-K-UNUSED: clang: warning: -K: 'linker' input unused [-Wunused-command-line-argument] diff --git a/clang/test/Driver/pch-inputs.h b/clang/test/Driver/pch-inputs.h index fa6f94f996915f..a1108e7bba40dd 100644 --- a/clang/test/Driver/pch-inputs.h +++ b/clang/test/Driver/pch-inputs.h @@ -4,10 +4,10 @@ // Warn about linker options being ignored when not linking // RUN: %clang %s -lfoo -o %t/tmp1.pch -### 2>&1 | FileCheck %s --check-prefix=UNUSED-L,SINGLEHEADER // RUN: %clang %s -x c++-header -lfoo -o %t/tmp1.pch -### 2>&1 | FileCheck %s --check-prefix=UNUSED-L,SINGLEHEADER -// UNUSED-L: clang: warning: -lfoo: 'linker' input unused [-Wunused-command-line-argument] +// UNUSED-L: clang: warning: -lfoo: 'linker' input unused when '' is present [-Wunused-command-line-argument] // RUN: %clang %s -Wl,--whole-archive -o %t/tmp1.pch -### 2>&1 | FileCheck %s --check-prefix=UNUSED-WL,SINGLEHEADER -// UNUSED-WL: clang: warning: -Wl,--whole-archive: 'linker' input unused [-Wunused-command-line-argument] +// UNUSED-WL: clang: warning: -Wl,--whole-archive: 'linker' input unused when '' is present [-Wunused-command-line-argument] // RUN: %clang %S/Inputs/header1.h %S/Inputs/header2.h -lfoo -### 2>&1 | FileCheck %s --check-prefix=UNUSED-L,MULTIHEADER @@ -23,7 +23,7 @@ // RUN: %clang -x cl-header %s -Xlinker -somelinkerflag -### 2>&1 | FileCheck %s --check-prefix=UNUSED-XLINKER // RUN: %clang -x objective-c++-header %s -Xlinker -somelinkerflag -### 2>&1 | FileCheck %s --check-prefix=UNUSED-XLINKER // RUN: %clang -x hlsl %s -Xlinker -somelinkerflag -### 2>&1 | FileCheck %s --check-prefix=UNUSED-XLINKER -// UNUSED-XLINKER: clang: warning: -Xlinker -somelinkerflag: 'linker' input unused [-Wunused-command-line-argument] +// UNUSED-XLINKER: clang: warning: -Xlinker -somelinkerflag: 'linker' input unused when '' is present [-Wunused-command-line-argument] // Normal case: Single header file input compiles to .pch even without --precompile @@ -44,5 +44,3 @@ // MULTIHEADER: "-emit-pch" // MULTIHEADER: "-o" // MULTIHEADER: header2.h.pch" - - >From c7d46dc90faa9929b370169374516d035c9a975f Mon Sep 17 00:00:00 2001 From: Michael Kruse <[email protected]> Date: Wed, 23 Sep 2026 12:49:04 +0200 Subject: [PATCH 4/4] clang-format --- clang/lib/Driver/Driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 8f3d4f803810f7..cba622553a3f3d 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -440,7 +440,7 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, void Driver::updateFinalPhase(Compilation &C, llvm::ArrayRef<InputTy> Inputs) const { Arg *FinalPhaseArg = nullptr; - phases ::ID FinalPhase = getFinalPhase(C.getArgs(), Inputs, &FinalPhaseArg); + phases::ID FinalPhase = getFinalPhase(C.getArgs(), Inputs, &FinalPhaseArg); C.setFinalPhase(FinalPhase, FinalPhaseArg); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
