diff --git a/clang/lib/Driver/ToolChains/Fuchsia.h b/clang/lib/Driver/ToolChains/Fuchsia.h --- a/clang/lib/Driver/ToolChains/Fuchsia.h +++ b/clang/lib/Driver/ToolChains/Fuchsia.h @@ -112,6 +112,10 @@ const char *getDefaultLinker() const override { return "ld.lld"; } + static void configureMultilibs(MultilibSet &); + static void configureMultilibFlags(Multilib::flags_list &, bool Exceptions, + bool Asan, bool Hwasan, bool Itanium); + protected: Tool *buildLinker() const override; Tool *buildStaticLibTool() const override; diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -260,6 +260,32 @@ return FP; }; + configureMultilibs(Multilibs); + + Multilibs.FilterOut([&](const Multilib &M) { + std::vector RD = FilePaths(M); + return llvm::all_of(RD, [&](std::string P) { return !getVFS().exists(P); }); + }); + + Multilib::flags_list Flags; + configureMultilibFlags( + Flags, + Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true), + getSanitizerArgs(Args).needsAsanRt(), + getSanitizerArgs(Args).needsHwasanRt(), + Args.getLastArgValue(options::OPT_fcxx_abi_EQ) == "itanium"); + + Multilibs.setFilePathsCallback(FilePaths); + + if (Multilibs.select(Flags, SelectedMultilib)) + if (!SelectedMultilib.isDefault()) + if (const auto &PathsCallback = Multilibs.filePathsCallback()) + for (const auto &Path : PathsCallback(SelectedMultilib)) + // Prepend the multilib path to ensure it takes the precedence. + getFilePaths().insert(getFilePaths().begin(), Path); +} + +void Fuchsia::configureMultilibs(MultilibSet &Multilibs) { Multilibs.push_back(Multilib()); // Use the noexcept variant with -fno-exceptions to avoid the extra overhead. Multilibs.push_back(Multilib("noexcept", {}, {}, 1) @@ -284,32 +310,16 @@ .flag("+fno-exceptions")); // Use Itanium C++ ABI for the compat multilib. Multilibs.push_back(Multilib("compat", {}, {}, 6).flag("+fc++-abi=itanium")); +} - Multilibs.FilterOut([&](const Multilib &M) { - std::vector RD = FilePaths(M); - return llvm::all_of(RD, [&](std::string P) { return !getVFS().exists(P); }); - }); - - Multilib::flags_list Flags; - addMultilibFlag( - Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true), - "fexceptions", Flags); - addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "fsanitize=address", - Flags); - addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), "fsanitize=hwaddress", - Flags); - - addMultilibFlag(Args.getLastArgValue(options::OPT_fcxx_abi_EQ) == "itanium", - "fc++-abi=itanium", Flags); - - Multilibs.setFilePathsCallback(FilePaths); - - if (Multilibs.select(Flags, SelectedMultilib)) - if (!SelectedMultilib.isDefault()) - if (const auto &PathsCallback = Multilibs.filePathsCallback()) - for (const auto &Path : PathsCallback(SelectedMultilib)) - // Prepend the multilib path to ensure it takes the precedence. - getFilePaths().insert(getFilePaths().begin(), Path); +void Fuchsia::configureMultilibFlags(Multilib::flags_list &Flags, + bool Exceptions, bool Asan, bool Hwasan, + bool Itanium) { + addMultilibFlag(Exceptions, "fexceptions", Flags); + addMultilibFlag(!Exceptions, "fno-exceptions", Flags); + addMultilibFlag(Asan, "fsanitize=address", Flags); + addMultilibFlag(Hwasan, "fsanitize=hwaddress", Flags); + addMultilibFlag(Itanium, "fc++-abi=itanium", Flags); } std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args, diff --git a/clang/unittests/Driver/CMakeLists.txt b/clang/unittests/Driver/CMakeLists.txt --- a/clang/unittests/Driver/CMakeLists.txt +++ b/clang/unittests/Driver/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangDriverTests DistroTest.cpp DXCModeTest.cpp + FuchsiaTest.cpp ToolChainTest.cpp ModuleCacheTest.cpp MultilibTest.cpp diff --git a/clang/unittests/Driver/FuchsiaTest.cpp b/clang/unittests/Driver/FuchsiaTest.cpp new file mode 100644 --- /dev/null +++ b/clang/unittests/Driver/FuchsiaTest.cpp @@ -0,0 +1,62 @@ +//===- unittests/Driver/FuchsiaTest.cpp --- Fuchsia tests ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Unit tests for Fuchsia +// +//===----------------------------------------------------------------------===// + +#include "../../lib/Driver/ToolChains/Fuchsia.h" +#include "gtest/gtest.h" + +using namespace clang::driver; + +/* +This test was added prior to changing the behaviour of Multilib. +The way that Fuchsia used Multilib made it very likely that the change +would cause it to break so by adding this exhaustive test we avoid that +possibility. +*/ +TEST(FuchsiaTest, MultilibVariant) { + MultilibSet Multilibs; + toolchains::Fuchsia::configureMultilibs(Multilibs); + + std::string Actual; + + for (bool Itanium : {false, true}) { + for (bool Hwasan : {false, true}) { + for (bool Asan : {false, true}) { + for (bool Exceptions : {false, true}) { + Multilib::flags_list Flags; + toolchains::Fuchsia::configureMultilibFlags(Flags, Exceptions, Asan, + Hwasan, Itanium); + Multilib Selected; + EXPECT_TRUE(Multilibs.select(Flags, Selected)); + Actual += Selected.gccSuffix() + "\n"; + } + } + } + } + std::string Expected = R"(/noexcept + +/asan+noexcept +/asan +/hwasan+noexcept +/hwasan +/hwasan+noexcept +/hwasan +/compat +/compat +/compat +/compat +/compat +/compat +/compat +/compat +)"; + EXPECT_EQ(Expected, Actual); +}