https://github.com/frobtech updated https://github.com/llvm/llvm-project/pull/236027
>From 13c174de0e0855d32b05fa2bfada27b62465db32 Mon Sep 17 00:00:00 2001 From: Roland McGrath <[email protected]> Date: Tue, 27 Oct 2026 00:48:42 -0700 Subject: [PATCH 1/2] [clang][Driver] Set *LinkerIsLLD for all LLD linker paths in GetLinkerPath ToolChain::GetLinkerPath(bool *LinkerIsLLD) previously only set *LinkerIsLLD when -fuse-ld=lld (or CLANG_DEFAULT_LINKER=lld) was used with a relative linker name or --ld-path=. It left *LinkerIsLLD false when the toolchain's default linker is ld.lld (such as on Fuchsia, FreeBSD, Android, Haiku, SerenityOS, Hexagon musl, or AMDGPU), when --ld-path= or an absolute -fuse-ld= path pointed to an ld.lld or ld64.lld binary without -fuse-ld=lld, or when falling back to a default ld.lld linker. Conversely, when CLANG_DEFAULT_LINKER=lld was configured, passing --ld-path= with a non-LLD linker (such as ld.bfd) without an explicit -fuse-ld= option erroneously set *LinkerIsLLD to true. Check whether the resolved linker filename matches ld.lld (or ld64.lld on Darwin), including versioned (ld.lld-<ver>) and target-prefixed (<triple>-ld.lld) names, across all code paths in GetLinkerPath. When --ld-path= is specified, only treat -fuse-ld=lld as overriding the path check when -fuse-ld=lld was explicitly passed on the command line. This also allows removing the duplicate linker filename checks in Hexagon's constructHexagonLinkArgs and tools::addLTOOptions. Assisted-by: Gemini --- clang/lib/Driver/ToolChain.cpp | 50 ++++++++++++++-------- clang/lib/Driver/ToolChains/CommonArgs.cpp | 8 ++-- clang/lib/Driver/ToolChains/Hexagon.cpp | 6 +-- clang/test/Driver/darwin-ld-demangle-lld.c | 15 ++++++- clang/test/Driver/fat-lto-objects.c | 4 ++ 5 files changed, 56 insertions(+), 27 deletions(-) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index b3e7043a64fe56..7ffbf6f5911381 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1310,9 +1310,26 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD) const { if (LinkerIsLLD) *LinkerIsLLD = false; + auto IsLLDPath = [&](StringRef Path) { + StringRef Name = llvm::sys::path::filename(Path); + Name.consume_back_insensitive(".exe"); + StringRef LLDName = Triple.isOSDarwin() ? "ld64.lld" : "ld.lld"; + return Name.starts_with_insensitive(LLDName) || + Name.ends_with_insensitive(LLDName); + }; + + auto GetDefaultLinkerPath = [&]() { + const char *DefaultLinker = getDefaultLinker(); + if (LinkerIsLLD) + *LinkerIsLLD = IsLLDPath(DefaultLinker); + if (llvm::sys::path::is_absolute(DefaultLinker)) + return std::string(DefaultLinker); + return GetProgramPath(DefaultLinker); + }; + // Get -fuse-ld= first to prevent -Wunused-command-line-argument. -fuse-ld= is // considered as the linker flavor, e.g. "bfd", "gold", or "lld". - const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ); + const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ); StringRef UseLinker = A ? A->getValue() : getDriver().getPreferredLinker(); // --ld-path= takes precedence over -fuse-ld= and specifies the executable @@ -1320,29 +1337,25 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD) const { // contain a path component separator. // -fuse-ld=lld can be used with --ld-path= to inform clang that the binary // that --ld-path= points to is lld. - if (const Arg *A = Args.getLastArg(options::OPT_ld_path_EQ)) { - std::string Path(A->getValue()); + if (const Arg *LdPathArg = Args.getLastArg(options::OPT_ld_path_EQ)) { + std::string Path(LdPathArg->getValue()); if (!Path.empty()) { if (llvm::sys::path::parent_path(Path).empty()) - Path = GetProgramPath(A->getValue()); + Path = GetProgramPath(LdPathArg->getValue()); if (llvm::sys::fs::can_execute(Path)) { if (LinkerIsLLD) - *LinkerIsLLD = UseLinker == "lld"; - return std::string(Path); + *LinkerIsLLD = (A && UseLinker == "lld") || IsLLDPath(Path); + return Path; } } - getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args); - return GetProgramPath(getDefaultLinker()); + getDriver().Diag(diag::err_drv_invalid_linker_name) + << LdPathArg->getAsString(Args); + return GetDefaultLinkerPath(); } // If we're passed -fuse-ld= with no argument, or with the argument ld, // then use whatever the default system linker is. - if (UseLinker.empty() || UseLinker == "ld") { - const char *DefaultLinker = getDefaultLinker(); - if (llvm::sys::path::is_absolute(DefaultLinker)) - return std::string(DefaultLinker); - else - return GetProgramPath(DefaultLinker); - } + if (UseLinker.empty() || UseLinker == "ld") + return GetDefaultLinkerPath(); // Extending -fuse-ld= to an absolute or relative path is unexpected. Checking // for the linker flavor is brittle. In addition, prepending "ld." or "ld64." @@ -1354,8 +1367,11 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD) const { if (llvm::sys::path::is_absolute(UseLinker)) { // If we're passed what looks like an absolute path, don't attempt to // second-guess that. - if (llvm::sys::fs::can_execute(UseLinker)) + if (llvm::sys::fs::can_execute(UseLinker)) { + if (LinkerIsLLD) + *LinkerIsLLD = IsLLDPath(UseLinker); return std::string(UseLinker); + } } else { llvm::SmallString<8> LinkerName; if (Triple.isOSDarwin()) @@ -1375,7 +1391,7 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD) const { if (A) getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args); - return GetProgramPath(getDefaultLinker()); + return GetDefaultLinkerPath(); } std::string ToolChain::GetStaticLibToolPath() const { diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 39dcec2f823bdd..cdee3823945f63 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1059,7 +1059,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, const bool IsOSAIX = Triple.isOSAIX(); const bool IsAMDGCN = Triple.isAMDGCN(); StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ); - const char *LinkerPath = Args.MakeArgString(ToolChain.GetLinkerPath()); + bool LinkerIsLLD = false; + (void)ToolChain.GetLinkerPath(&LinkerIsLLD); const Driver &D = ToolChain.getDriver(); const bool IsFatLTO = Args.hasFlag(options::OPT_ffat_lto_objects, options::OPT_fno_fat_lto_objects, false); @@ -1075,9 +1076,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, Input = Inputs.begin(); } - if (Linker != "lld" && Linker != "lld-link" && - llvm::sys::path::filename(LinkerPath) != "ld.lld" && - llvm::sys::path::stem(LinkerPath) != "ld.lld" && !Triple.isOSOpenBSD()) { + if (!LinkerIsLLD && Linker != "lld" && Linker != "lld-link" && + !Triple.isOSOpenBSD()) { // Tell the linker to load the plugin. This has to come before // AddLinkerInputs as gold requires -plugin and AIX ld requires -bplugin to // come before any -plugin-opt/-bplugin_opt that -Wl might forward. diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index 9c823a847d6e33..6e9b23849f61ab 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -301,11 +301,7 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles); bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); bool UseLLD = false; - const char *Exec = Args.MakeArgString(HTC.GetLinkerPath(&UseLLD)); - StringRef LinkerName = llvm::sys::path::filename(Exec); - UseLLD = UseLLD || LinkerName.starts_with("ld.lld") || - LinkerName.ends_with("ld.lld") || - llvm::sys::path::stem(Exec).ends_with("ld.lld"); + (void)HTC.GetLinkerPath(&UseLLD); bool UseShared = IsShared && !IsStatic; StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); diff --git a/clang/test/Driver/darwin-ld-demangle-lld.c b/clang/test/Driver/darwin-ld-demangle-lld.c index 4edeb1058b933f..592ca2374bf644 100644 --- a/clang/test/Driver/darwin-ld-demangle-lld.c +++ b/clang/test/Driver/darwin-ld-demangle-lld.c @@ -1,4 +1,4 @@ -// With -fuse-ld=lld, -demangle is always passed to the linker on Darwin. +// With LLD, -demangle is always passed to the linker on Darwin. // RUN: %clang --target=x86_64-apple-darwin -### -fuse-ld=lld \ // RUN: -B%S/Inputs/lld -mlinker-version=0 %s 2>&1 \ @@ -8,4 +8,17 @@ // RUN: --ld-path=%S/Inputs/lld/ld64.lld -mlinker-version=0 %s 2>&1 \ // RUN: | FileCheck %s +// RUN: %clang --target=x86_64-apple-darwin -### \ +// RUN: --ld-path=%S/Inputs/lld/ld64.lld -mlinker-version=0 %s 2>&1 \ +// RUN: | FileCheck %s + +// RUN: %clang --target=x86_64-apple-darwin -### -Wno-fuse-ld-path \ +// RUN: -fuse-ld=%S/Inputs/lld/ld64.lld -mlinker-version=0 %s 2>&1 \ +// RUN: | FileCheck %s + +// RUN: %clang --target=x86_64-apple-darwin -### \ +// RUN: --ld-path=%S/Inputs/lld/ld.lld -mlinker-version=0 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=NO-DEMANGLE %s + // CHECK: "-demangle" +// NO-DEMANGLE-NOT: "-demangle" diff --git a/clang/test/Driver/fat-lto-objects.c b/clang/test/Driver/fat-lto-objects.c index 84dd945e208b9e..b97ad0efb16c7c 100644 --- a/clang/test/Driver/fat-lto-objects.c +++ b/clang/test/Driver/fat-lto-objects.c @@ -60,5 +60,9 @@ // RUN: %clang --target=x86_64-unknown-linux-gnu --sysroot=%S/Inputs/basic_cross_linux_tree %s \ // RUN: -fuse-ld=lld --ld-path=%S/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/lld-wrapper \ // RUN: -flto -ffat-lto-objects -### 2>&1 | FileCheck --check-prefix=LTO %s +// RUN: %clang --target=x86_64-unknown-linux-gnu --sysroot=%S/Inputs/basic_cross_linux_tree %s \ +// RUN: --ld-path=%S/Inputs/lld/ld.lld -flto -ffat-lto-objects -### 2>&1 | FileCheck --check-prefix=LTO %s +// RUN: %clang --target=x86_64-unknown-fuchsia %s \ +// RUN: -B%S/Inputs/lld -flto -ffat-lto-objects -### 2>&1 | FileCheck --check-prefix=LTO %s // LTO: "--fat-lto-objects" // NOLTO-NOT: "--fat-lto-objects" >From b999ec36e7ce97380c9925b2f4b6267fc9052171 Mon Sep 17 00:00:00 2001 From: Roland McGrath <[email protected]> Date: Thu, 29 Oct 2026 12:46:00 -0700 Subject: [PATCH 2/2] [clang][Driver] Address review comments in CommonArgs and Hexagon Remove redundant Linker != "lld" && Linker != "lld-link" check in tools::addLTOOptions now covered by ToolChain::GetLinkerPath, and hoist HTC.GetLinkerPath(&UseLLD) into hexagon::Linker::ConstructJob. Assisted-by: Gemini --- clang/lib/Driver/ToolChains/CommonArgs.cpp | 4 +--- clang/lib/Driver/ToolChains/Hexagon.cpp | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index cdee3823945f63..6714e8594ee5b6 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1058,7 +1058,6 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, const llvm::Triple &Triple = ToolChain.getTriple(); const bool IsOSAIX = Triple.isOSAIX(); const bool IsAMDGCN = Triple.isAMDGCN(); - StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ); bool LinkerIsLLD = false; (void)ToolChain.GetLinkerPath(&LinkerIsLLD); const Driver &D = ToolChain.getDriver(); @@ -1076,8 +1075,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, Input = Inputs.begin(); } - if (!LinkerIsLLD && Linker != "lld" && Linker != "lld-link" && - !Triple.isOSOpenBSD()) { + if (!LinkerIsLLD && !Triple.isOSOpenBSD()) { // Tell the linker to load the plugin. This has to come before // AddLinkerInputs as gold requires -plugin and AIX ld requires -bplugin to // come before any -plugin-opt/-bplugin_opt that -Wl might forward. diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index 6e9b23849f61ab..c43dee12741ab2 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -281,12 +281,13 @@ void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { } -static void -constructHexagonLinkArgs(Compilation &C, const JobAction &JA, - const toolchains::HexagonToolChain &HTC, - const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &Args, ArgStringList &CmdArgs, - const char *LinkingOutput) { +static void constructHexagonLinkArgs(Compilation &C, const JobAction &JA, + const toolchains::HexagonToolChain &HTC, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + ArgStringList &CmdArgs, + const char *LinkingOutput, bool UseLLD) { const Driver &D = HTC.getDriver(); @@ -300,8 +301,6 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, bool IncStdLib = !Args.hasArg(options::OPT_nostdlib); bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles); bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); - bool UseLLD = false; - (void)HTC.GetLinkerPath(&UseLLD); bool UseShared = IsShared && !IsStatic; StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); @@ -547,11 +546,13 @@ void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); + bool UseLLD = false; + const char *Exec = Args.MakeArgString(HTC.GetLinkerPath(&UseLLD)); + ArgStringList CmdArgs; constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs, - LinkingOutput); + LinkingOutput, UseLLD); - const char *Exec = Args.MakeArgString(HTC.GetLinkerPath()); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
