[clang] 850dab0 - [NFC] Class for building MultilibSet

Michael Platings via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 22 01:28:39 PST 2023


Author: Michael Platings
Date: 2023-02-22T09:24:48Z
New Revision: 850dab0f2537bb31103578fc35caef2f1ad98f04

URL: https://github.com/llvm/llvm-project/commit/850dab0f2537bb31103578fc35caef2f1ad98f04
DIFF: https://github.com/llvm/llvm-project/commit/850dab0f2537bb31103578fc35caef2f1ad98f04.diff

LOG: [NFC] Class for building MultilibSet

The functionality in MultilibSet for creating it is tied to its current
implementation. Putting that code in a separate class is an enabler for
changing the MultilibSet implementation.

Differential Revision: https://reviews.llvm.org/D142893

Added: 
    clang/include/clang/Driver/MultilibBuilder.h
    clang/lib/Driver/MultilibBuilder.cpp
    clang/unittests/Driver/MultilibBuilderTest.cpp

Modified: 
    clang/include/clang/Driver/Multilib.h
    clang/lib/Driver/CMakeLists.txt
    clang/lib/Driver/Multilib.cpp
    clang/lib/Driver/ToolChains/BareMetal.cpp
    clang/lib/Driver/ToolChains/Fuchsia.cpp
    clang/lib/Driver/ToolChains/Gnu.cpp
    clang/unittests/Driver/CMakeLists.txt
    clang/unittests/Driver/MultilibTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h
index cf2dbf6ff58a6..feb12f3638d34 100644
--- a/clang/include/clang/Driver/Multilib.h
+++ b/clang/include/clang/Driver/Multilib.h
@@ -24,7 +24,9 @@ namespace clang {
 namespace driver {
 
 /// This corresponds to a single GCC Multilib, or a segment of one controlled
-/// by a command line flag
+/// by a command line flag.
+/// See also MultilibBuilder for building a multilib by mutating it
+/// incrementally.
 class Multilib {
 public:
   using flags_list = std::vector<std::string>;
@@ -37,71 +39,37 @@ class Multilib {
   int Priority;
 
 public:
+  /// GCCSuffix, OSSuffix & IncludeSuffix will be appended directly to the
+  /// sysroot string so they must either be empty or begin with a '/' character.
+  /// This is enforced with an assert in the constructor.
   Multilib(StringRef GCCSuffix = {}, StringRef OSSuffix = {},
-           StringRef IncludeSuffix = {}, int Priority = 0);
+           StringRef IncludeSuffix = {}, int Priority = 0,
+           const flags_list &Flags = flags_list());
 
   /// Get the detected GCC installation path suffix for the multi-arch
   /// target variant. Always starts with a '/', unless empty
-  const std::string &gccSuffix() const {
-    assert(GCCSuffix.empty() ||
-           (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1));
-    return GCCSuffix;
-  }
-
-  /// Set the GCC installation path suffix.
-  Multilib &gccSuffix(StringRef S);
+  const std::string &gccSuffix() const { return GCCSuffix; }
 
   /// Get the detected os path suffix for the multi-arch
   /// target variant. Always starts with a '/', unless empty
-  const std::string &osSuffix() const {
-    assert(OSSuffix.empty() ||
-           (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1));
-    return OSSuffix;
-  }
-
-  /// Set the os path suffix.
-  Multilib &osSuffix(StringRef S);
+  const std::string &osSuffix() const { return OSSuffix; }
 
   /// Get the include directory suffix. Always starts with a '/', unless
   /// empty
-  const std::string &includeSuffix() const {
-    assert(IncludeSuffix.empty() ||
-           (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1));
-    return IncludeSuffix;
-  }
-
-  /// Set the include directory suffix
-  Multilib &includeSuffix(StringRef S);
+  const std::string &includeSuffix() const { return IncludeSuffix; }
 
   /// Get the flags that indicate or contraindicate this multilib's use
   /// All elements begin with either '+' or '-'
   const flags_list &flags() const { return Flags; }
-  flags_list &flags() { return Flags; }
 
   /// Returns the multilib priority. When more than one multilib matches flags,
   /// the one with the highest priority is selected, with 0 being the default.
   int priority() const { return Priority; }
 
-  /// Add a flag to the flags list
-  /// \p Flag must be a flag accepted by the driver with its leading '-' removed,
-  ///     and replaced with either:
-  ///       '-' which contraindicates using this multilib with that flag
-  ///     or:
-  ///       '+' which promotes using this multilib in the presence of that flag
-  ///     otherwise '-print-multi-lib' will not emit them correctly.
-  Multilib &flag(StringRef F) {
-    assert(F.front() == '+' || F.front() == '-');
-    Flags.push_back(std::string(F));
-    return *this;
-  }
-
   LLVM_DUMP_METHOD void dump() const;
   /// print summary of the Multilib
   void print(raw_ostream &OS) const;
 
-  /// Check whether any of the 'against' flags contradict the 'for' flags.
-  bool isValid() const;
-
   /// Check whether the default is selected
   bool isDefault() const
   { return GCCSuffix.empty() && OSSuffix.empty() && IncludeSuffix.empty(); }
@@ -111,10 +79,10 @@ class Multilib {
 
 raw_ostream &operator<<(raw_ostream &OS, const Multilib &M);
 
+/// See also MultilibSetBuilder for combining multilibs into a set.
 class MultilibSet {
 public:
   using multilib_list = std::vector<Multilib>;
-  using iterator = multilib_list::iterator;
   using const_iterator = multilib_list::const_iterator;
   using IncludeDirsFunc =
       std::function<std::vector<std::string>(const Multilib &M)>;
@@ -127,40 +95,17 @@ class MultilibSet {
 
 public:
   MultilibSet() = default;
+  MultilibSet(multilib_list &&Multilibs) : Multilibs(Multilibs) {}
 
-  /// Add an optional Multilib segment
-  MultilibSet &Maybe(const Multilib &M);
-
-  /// Add a set of mutually incompatible Multilib segments
-  MultilibSet &Either(const Multilib &M1, const Multilib &M2);
-  MultilibSet &Either(const Multilib &M1, const Multilib &M2,
-                      const Multilib &M3);
-  MultilibSet &Either(const Multilib &M1, const Multilib &M2,
-                      const Multilib &M3, const Multilib &M4);
-  MultilibSet &Either(const Multilib &M1, const Multilib &M2,
-                      const Multilib &M3, const Multilib &M4,
-                      const Multilib &M5);
-  MultilibSet &Either(ArrayRef<Multilib> Ms);
+  const multilib_list &getMultilibs() { return Multilibs; }
 
   /// Filter out some subset of the Multilibs using a user defined callback
   MultilibSet &FilterOut(FilterCallback F);
 
-  /// Filter out those Multilibs whose gccSuffix matches the given expression
-  MultilibSet &FilterOut(const char *Regex);
-
   /// Add a completed Multilib to the set
   void push_back(const Multilib &M);
 
-  /// Union this set of multilibs with another
-  void combineWith(const MultilibSet &MS);
-
-  /// Remove all of the multilibs from the set
-  void clear() { Multilibs.clear(); }
-
-  iterator begin() { return Multilibs.begin(); }
   const_iterator begin() const { return Multilibs.begin(); }
-
-  iterator end() { return Multilibs.end(); }
   const_iterator end() const { return Multilibs.end(); }
 
   /// Pick the best multilib in the set, \returns false if none are compatible

diff  --git a/clang/include/clang/Driver/MultilibBuilder.h b/clang/include/clang/Driver/MultilibBuilder.h
new file mode 100644
index 0000000000000..cf84c456152b1
--- /dev/null
+++ b/clang/include/clang/Driver/MultilibBuilder.h
@@ -0,0 +1,148 @@
+//===- MultilibBuilder.h
+//-----------------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_DRIVER_MULTILIBBUILDER_H
+#define LLVM_CLANG_DRIVER_MULTILIBBUILDER_H
+
+#include "clang/Driver/Multilib.h"
+
+namespace clang {
+namespace driver {
+
+/// This corresponds to a single GCC multilib, or a segment of one controlled
+/// by a command line flag. This class can be used to create a Multilib, and
+/// contains helper functions to mutate it before creating a Multilib instance
+/// with makeMultilib().
+class MultilibBuilder {
+public:
+  using flags_list = std::vector<std::string>;
+
+private:
+  std::string GCCSuffix;
+  std::string OSSuffix;
+  std::string IncludeSuffix;
+  flags_list Flags;
+  int Priority;
+
+public:
+  MultilibBuilder(StringRef GCCSuffix, StringRef OSSuffix,
+                  StringRef IncludeSuffix, int Priority = 0);
+
+  /// Initializes GCCSuffix, OSSuffix & IncludeSuffix to the same value.
+  MultilibBuilder(StringRef Suffix = {});
+
+  /// Get the detected GCC installation path suffix for the multi-arch
+  /// target variant. Always starts with a '/', unless empty
+  const std::string &gccSuffix() const {
+    assert(GCCSuffix.empty() ||
+           (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1));
+    return GCCSuffix;
+  }
+
+  /// Set the GCC installation path suffix.
+  MultilibBuilder &gccSuffix(StringRef S);
+
+  /// Get the detected os path suffix for the multi-arch
+  /// target variant. Always starts with a '/', unless empty
+  const std::string &osSuffix() const {
+    assert(OSSuffix.empty() ||
+           (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1));
+    return OSSuffix;
+  }
+
+  /// Set the os path suffix.
+  MultilibBuilder &osSuffix(StringRef S);
+
+  /// Get the include directory suffix. Always starts with a '/', unless
+  /// empty
+  const std::string &includeSuffix() const {
+    assert(IncludeSuffix.empty() || (StringRef(IncludeSuffix).front() == '/' &&
+                                     IncludeSuffix.size() > 1));
+    return IncludeSuffix;
+  }
+
+  /// Set the include directory suffix
+  MultilibBuilder &includeSuffix(StringRef S);
+
+  /// Get the flags that indicate or contraindicate this multilib's use
+  /// All elements begin with either '+' or '-'
+  const flags_list &flags() const { return Flags; }
+  flags_list &flags() { return Flags; }
+
+  /// Returns the multilib priority. When more than one multilib matches flags,
+  /// the one with the highest priority is selected, with 0 being the default.
+  int priority() const { return Priority; }
+
+  /// Add a flag to the flags list
+  /// \p Flag must be a flag accepted by the driver with its leading '-'
+  /// removed,
+  ///     and replaced with either:
+  ///       '-' which contraindicates using this multilib with that flag
+  ///     or:
+  ///       '+' which promotes using this multilib in the presence of that flag
+  ///     otherwise '-print-multi-lib' will not emit them correctly.
+  MultilibBuilder &flag(StringRef F) {
+    assert(F.front() == '+' || F.front() == '-');
+    Flags.push_back(std::string(F));
+    return *this;
+  }
+
+  Multilib makeMultilib() const;
+
+  /// Check whether any of the 'against' flags contradict the 'for' flags.
+  bool isValid() const;
+
+  /// Check whether the default is selected
+  bool isDefault() const {
+    return GCCSuffix.empty() && OSSuffix.empty() && IncludeSuffix.empty();
+  }
+};
+
+/// This class can be used to create a MultilibSet, and contains helper
+/// functions to add combinations of multilibs before creating a MultilibSet
+/// instance with makeMultilibSet().
+class MultilibSetBuilder {
+public:
+  using multilib_list = std::vector<MultilibBuilder>;
+
+  MultilibSetBuilder() = default;
+
+  /// Add an optional Multilib segment
+  MultilibSetBuilder &Maybe(const MultilibBuilder &M);
+
+  /// Add a set of mutually incompatible Multilib segments
+  MultilibSetBuilder &Either(const MultilibBuilder &M1,
+                             const MultilibBuilder &M2);
+  MultilibSetBuilder &Either(const MultilibBuilder &M1,
+                             const MultilibBuilder &M2,
+                             const MultilibBuilder &M3);
+  MultilibSetBuilder &Either(const MultilibBuilder &M1,
+                             const MultilibBuilder &M2,
+                             const MultilibBuilder &M3,
+                             const MultilibBuilder &M4);
+  MultilibSetBuilder &Either(const MultilibBuilder &M1,
+                             const MultilibBuilder &M2,
+                             const MultilibBuilder &M3,
+                             const MultilibBuilder &M4,
+                             const MultilibBuilder &M5);
+  MultilibSetBuilder &Either(ArrayRef<MultilibBuilder> Ms);
+
+  /// Filter out those Multilibs whose gccSuffix matches the given expression
+  MultilibSetBuilder &FilterOut(const char *Regex);
+
+  MultilibSet makeMultilibSet() const;
+
+private:
+  multilib_list Multilibs;
+};
+
+} // namespace driver
+} // namespace clang
+
+#endif // LLVM_CLANG_DRIVER_MULTILIBBUILDER_H

diff  --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt
index ba56a9323400c..e0bf3efc44c20 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -22,6 +22,7 @@ add_clang_library(clangDriver
   DriverOptions.cpp
   Job.cpp
   Multilib.cpp
+  MultilibBuilder.cpp
   OffloadBundler.cpp
   OptionUtils.cpp
   Phases.cpp

diff  --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp
index ec619874ad607..1f8db753e8233 100644
--- a/clang/lib/Driver/Multilib.cpp
+++ b/clang/lib/Driver/Multilib.cpp
@@ -25,56 +25,17 @@ using namespace clang;
 using namespace driver;
 using namespace llvm::sys;
 
-/// normalize Segment to "/foo/bar" or "".
-static void normalizePathSegment(std::string &Segment) {
-  StringRef seg = Segment;
-
-  // Prune trailing "/" or "./"
-  while (true) {
-    StringRef last = path::filename(seg);
-    if (last != ".")
-      break;
-    seg = path::parent_path(seg);
-  }
-
-  if (seg.empty() || seg == "/") {
-    Segment.clear();
-    return;
-  }
-
-  // Add leading '/'
-  if (seg.front() != '/') {
-    Segment = "/" + seg.str();
-  } else {
-    Segment = std::string(seg);
-  }
-}
-
 Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix,
-                   StringRef IncludeSuffix, int Priority)
+                   StringRef IncludeSuffix, int Priority,
+                   const flags_list &Flags)
     : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix),
-      Priority(Priority) {
-  normalizePathSegment(this->GCCSuffix);
-  normalizePathSegment(this->OSSuffix);
-  normalizePathSegment(this->IncludeSuffix);
-}
-
-Multilib &Multilib::gccSuffix(StringRef S) {
-  GCCSuffix = std::string(S);
-  normalizePathSegment(GCCSuffix);
-  return *this;
-}
-
-Multilib &Multilib::osSuffix(StringRef S) {
-  OSSuffix = std::string(S);
-  normalizePathSegment(OSSuffix);
-  return *this;
-}
-
-Multilib &Multilib::includeSuffix(StringRef S) {
-  IncludeSuffix = std::string(S);
-  normalizePathSegment(IncludeSuffix);
-  return *this;
+      Flags(Flags), Priority(Priority) {
+  assert(GCCSuffix.empty() ||
+         (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1));
+  assert(OSSuffix.empty() ||
+         (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1));
+  assert(IncludeSuffix.empty() ||
+         (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1));
 }
 
 LLVM_DUMP_METHOD void Multilib::dump() const {
@@ -82,7 +43,6 @@ LLVM_DUMP_METHOD void Multilib::dump() const {
 }
 
 void Multilib::print(raw_ostream &OS) const {
-  assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/'));
   if (GCCSuffix.empty())
     OS << ".";
   else {
@@ -95,22 +55,6 @@ void Multilib::print(raw_ostream &OS) const {
   }
 }
 
-bool Multilib::isValid() const {
-  llvm::StringMap<int> FlagSet;
-  for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
-    StringRef Flag(Flags[I]);
-    llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1));
-
-    assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-');
-
-    if (SI == FlagSet.end())
-      FlagSet[Flag.substr(1)] = I;
-    else if (Flags[I] != Flags[SI->getValue()])
-      return false;
-  }
-  return true;
-}
-
 bool Multilib::operator==(const Multilib &Other) const {
   // Check whether the flags sets match
   // allowing for the match to be order invariant
@@ -139,102 +83,13 @@ raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) {
   return OS;
 }
 
-MultilibSet &MultilibSet::Maybe(const Multilib &M) {
-  Multilib Opposite;
-  // Negate any '+' flags
-  for (StringRef Flag : M.flags()) {
-    if (Flag.front() == '+')
-      Opposite.flags().push_back(("-" + Flag.substr(1)).str());
-  }
-  return Either(M, Opposite);
-}
-
-MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) {
-  return Either({M1, M2});
-}
-
-MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
-                                 const Multilib &M3) {
-  return Either({M1, M2, M3});
-}
-
-MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
-                                 const Multilib &M3, const Multilib &M4) {
-  return Either({M1, M2, M3, M4});
-}
-
-MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
-                                 const Multilib &M3, const Multilib &M4,
-                                 const Multilib &M5) {
-  return Either({M1, M2, M3, M4, M5});
-}
-
-static Multilib compose(const Multilib &Base, const Multilib &New) {
-  SmallString<128> GCCSuffix;
-  llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
-  SmallString<128> OSSuffix;
-  llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
-  SmallString<128> IncludeSuffix;
-  llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
-                          New.includeSuffix());
-
-  Multilib Composed(GCCSuffix, OSSuffix, IncludeSuffix);
-
-  Multilib::flags_list &Flags = Composed.flags();
-
-  Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
-  Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
-
-  return Composed;
-}
-
-MultilibSet &MultilibSet::Either(ArrayRef<Multilib> MultilibSegments) {
-  multilib_list Composed;
-
-  if (Multilibs.empty())
-    Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
-                     MultilibSegments.end());
-  else {
-    for (const auto &New : MultilibSegments) {
-      for (const auto &Base : *this) {
-        Multilib MO = compose(Base, New);
-        if (MO.isValid())
-          Composed.push_back(MO);
-      }
-    }
-
-    Multilibs = Composed;
-  }
-
-  return *this;
-}
-
 MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
   filterInPlace(F, Multilibs);
   return *this;
 }
 
-MultilibSet &MultilibSet::FilterOut(const char *Regex) {
-  llvm::Regex R(Regex);
-#ifndef NDEBUG
-  std::string Error;
-  if (!R.isValid(Error)) {
-    llvm::errs() << Error;
-    llvm_unreachable("Invalid regex!");
-  }
-#endif
-
-  filterInPlace([&R](const Multilib &M) { return R.match(M.gccSuffix()); },
-                Multilibs);
-  return *this;
-}
-
 void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
 
-void MultilibSet::combineWith(const MultilibSet &Other) {
-  Multilibs.insert(Multilibs.end(), Other.begin(), Other.end());
-}
-
 static bool isFlagEnabled(StringRef Flag) {
   char Indicator = Flag.front();
   assert(Indicator == '+' || Indicator == '-');

diff  --git a/clang/lib/Driver/MultilibBuilder.cpp b/clang/lib/Driver/MultilibBuilder.cpp
new file mode 100644
index 0000000000000..83ebc31d8eb99
--- /dev/null
+++ b/clang/lib/Driver/MultilibBuilder.cpp
@@ -0,0 +1,192 @@
+//===- MultilibBuilder.cpp - MultilibBuilder Implementation -===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/MultilibBuilder.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace driver;
+
+/// normalize Segment to "/foo/bar" or "".
+static void normalizePathSegment(std::string &Segment) {
+  StringRef seg = Segment;
+
+  // Prune trailing "/" or "./"
+  while (true) {
+    StringRef last = llvm::sys::path::filename(seg);
+    if (last != ".")
+      break;
+    seg = llvm::sys::path::parent_path(seg);
+  }
+
+  if (seg.empty() || seg == "/") {
+    Segment.clear();
+    return;
+  }
+
+  // Add leading '/'
+  if (seg.front() != '/') {
+    Segment = "/" + seg.str();
+  } else {
+    Segment = std::string(seg);
+  }
+}
+
+MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include,
+                                 int Priority)
+    : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include), Priority(Priority) {
+  normalizePathSegment(GCCSuffix);
+  normalizePathSegment(OSSuffix);
+  normalizePathSegment(IncludeSuffix);
+}
+
+MultilibBuilder::MultilibBuilder(StringRef Suffix)
+    : MultilibBuilder(Suffix, Suffix, Suffix) {}
+
+MultilibBuilder &MultilibBuilder::gccSuffix(StringRef S) {
+  GCCSuffix = std::string(S);
+  normalizePathSegment(GCCSuffix);
+  return *this;
+}
+
+MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) {
+  OSSuffix = std::string(S);
+  normalizePathSegment(OSSuffix);
+  return *this;
+}
+
+MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) {
+  IncludeSuffix = std::string(S);
+  normalizePathSegment(IncludeSuffix);
+  return *this;
+}
+
+bool MultilibBuilder::isValid() const {
+  llvm::StringMap<int> FlagSet;
+  for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
+    StringRef Flag(Flags[I]);
+    llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1));
+
+    assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-');
+
+    if (SI == FlagSet.end())
+      FlagSet[Flag.substr(1)] = I;
+    else if (Flags[I] != Flags[SI->getValue()])
+      return false;
+  }
+  return true;
+}
+
+Multilib MultilibBuilder::makeMultilib() const {
+  return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Priority, Flags);
+}
+
+MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) {
+  MultilibBuilder Opposite;
+  // Negate any '+' flags
+  for (StringRef Flag : M.flags()) {
+    if (Flag.front() == '+')
+      Opposite.flags().push_back(("-" + Flag.substr(1)).str());
+  }
+  return Either(M, Opposite);
+}
+
+MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
+                                               const MultilibBuilder &M2) {
+  return Either({M1, M2});
+}
+
+MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
+                                               const MultilibBuilder &M2,
+                                               const MultilibBuilder &M3) {
+  return Either({M1, M2, M3});
+}
+
+MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
+                                               const MultilibBuilder &M2,
+                                               const MultilibBuilder &M3,
+                                               const MultilibBuilder &M4) {
+  return Either({M1, M2, M3, M4});
+}
+
+MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
+                                               const MultilibBuilder &M2,
+                                               const MultilibBuilder &M3,
+                                               const MultilibBuilder &M4,
+                                               const MultilibBuilder &M5) {
+  return Either({M1, M2, M3, M4, M5});
+}
+
+static MultilibBuilder compose(const MultilibBuilder &Base,
+                               const MultilibBuilder &New) {
+  SmallString<128> GCCSuffix;
+  llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
+  SmallString<128> OSSuffix;
+  llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
+  SmallString<128> IncludeSuffix;
+  llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
+                          New.includeSuffix());
+
+  MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix);
+
+  MultilibBuilder::flags_list &Flags = Composed.flags();
+
+  Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
+  Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
+
+  return Composed;
+}
+
+MultilibSetBuilder &
+MultilibSetBuilder::Either(ArrayRef<MultilibBuilder> MultilibSegments) {
+  multilib_list Composed;
+
+  if (Multilibs.empty())
+    Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
+                     MultilibSegments.end());
+  else {
+    for (const auto &New : MultilibSegments) {
+      for (const auto &Base : Multilibs) {
+        MultilibBuilder MO = compose(Base, New);
+        if (MO.isValid())
+          Composed.push_back(MO);
+      }
+    }
+
+    Multilibs = Composed;
+  }
+
+  return *this;
+}
+
+MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) {
+  llvm::Regex R(Regex);
+#ifndef NDEBUG
+  std::string Error;
+  if (!R.isValid(Error)) {
+    llvm::errs() << Error;
+    llvm_unreachable("Invalid regex!");
+  }
+#endif
+  llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) {
+    return R.match(M.gccSuffix());
+  });
+  return *this;
+}
+
+MultilibSet MultilibSetBuilder::makeMultilibSet() const {
+  MultilibSet Result;
+  for (const auto &M : Multilibs) {
+    Result.push_back(M.makeMultilib());
+  }
+  return Result;
+}

diff  --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp
index ac9c7036ad6ef..3175b15a48ca7 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -16,6 +16,7 @@
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/MultilibBuilder.h"
 #include "clang/Driver/Options.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/Path.h"
@@ -28,10 +29,6 @@ using namespace clang::driver;
 using namespace clang::driver::tools;
 using namespace clang::driver::toolchains;
 
-static Multilib makeMultilib(StringRef commonSuffix) {
-  return Multilib(commonSuffix, commonSuffix, commonSuffix);
-}
-
 static bool findRISCVMultilibs(const Driver &D,
                                const llvm::Triple &TargetTriple,
                                const ArgList &Args, DetectedMultilibs &Result) {
@@ -40,10 +37,11 @@ static bool findRISCVMultilibs(const Driver &D,
   StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
 
   if (TargetTriple.isRISCV64()) {
-    Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64");
-    Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d")
-                          .flag("+march=rv64imafdc")
-                          .flag("+mabi=lp64d");
+    MultilibBuilder Imac =
+        MultilibBuilder().flag("+march=rv64imac").flag("+mabi=lp64");
+    MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d")
+                                 .flag("+march=rv64imafdc")
+                                 .flag("+mabi=lp64d");
 
     // Multilib reuse
     bool UseImafdc =
@@ -54,22 +52,25 @@ static bool findRISCVMultilibs(const Driver &D,
     addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags);
     addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags);
 
-    Result.Multilibs = MultilibSet().Either(Imac, Imafdc);
+    Result.Multilibs =
+        MultilibSetBuilder().Either(Imac, Imafdc).makeMultilibSet();
     return Result.Multilibs.select(Flags, Result.SelectedMultilib);
   }
   if (TargetTriple.isRISCV32()) {
-    Multilib Imac =
-        makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32");
-    Multilib I =
-        makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32");
-    Multilib Im =
-        makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32");
-    Multilib Iac = makeMultilib("/rv32iac/ilp32")
-                       .flag("+march=rv32iac")
-                       .flag("+mabi=ilp32");
-    Multilib Imafc = makeMultilib("/rv32imafc/ilp32f")
-                         .flag("+march=rv32imafc")
-                         .flag("+mabi=ilp32f");
+    MultilibBuilder Imac =
+        MultilibBuilder().flag("+march=rv32imac").flag("+mabi=ilp32");
+    MultilibBuilder I = MultilibBuilder("/rv32i/ilp32")
+                            .flag("+march=rv32i")
+                            .flag("+mabi=ilp32");
+    MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32")
+                             .flag("+march=rv32im")
+                             .flag("+mabi=ilp32");
+    MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32")
+                              .flag("+march=rv32iac")
+                              .flag("+mabi=ilp32");
+    MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f")
+                                .flag("+march=rv32imafc")
+                                .flag("+mabi=ilp32f");
 
     // Multilib reuse
     bool UseI = (Arch == "rv32i") || (Arch == "rv32ic");    // ic => i
@@ -85,7 +86,8 @@ static bool findRISCVMultilibs(const Driver &D,
     addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags);
     addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags);
 
-    Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc);
+    Result.Multilibs =
+        MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet();
     return Result.Multilibs.select(Flags, Result.SelectedMultilib);
   }
   return false;

diff  --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp
index 36bd93a4913c6..3a3f7043a795f 100644
--- a/clang/lib/Driver/ToolChains/Fuchsia.cpp
+++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp
@@ -12,6 +12,7 @@
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/MultilibBuilder.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/SanitizerArgs.h"
 #include "llvm/Option/ArgList.h"
@@ -262,28 +263,35 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
 
   Multilibs.push_back(Multilib());
   // Use the noexcept variant with -fno-exceptions to avoid the extra overhead.
-  Multilibs.push_back(Multilib("noexcept", {}, {}, 1)
+  Multilibs.push_back(MultilibBuilder("noexcept", {}, {}, 1)
                           .flag("-fexceptions")
-                          .flag("+fno-exceptions"));
+                          .flag("+fno-exceptions")
+                          .makeMultilib());
   // ASan has higher priority because we always want the instrumentated version.
-  Multilibs.push_back(Multilib("asan", {}, {}, 2)
-                          .flag("+fsanitize=address"));
+  Multilibs.push_back(MultilibBuilder("asan", {}, {}, 2)
+                          .flag("+fsanitize=address")
+                          .makeMultilib());
   // Use the asan+noexcept variant with ASan and -fno-exceptions.
-  Multilibs.push_back(Multilib("asan+noexcept", {}, {}, 3)
+  Multilibs.push_back(MultilibBuilder("asan+noexcept", {}, {}, 3)
                           .flag("+fsanitize=address")
                           .flag("-fexceptions")
-                          .flag("+fno-exceptions"));
+                          .flag("+fno-exceptions")
+                          .makeMultilib());
   // HWASan has higher priority because we always want the instrumentated
   // version.
-  Multilibs.push_back(
-      Multilib("hwasan", {}, {}, 4).flag("+fsanitize=hwaddress"));
+  Multilibs.push_back(MultilibBuilder("hwasan", {}, {}, 4)
+                          .flag("+fsanitize=hwaddress")
+                          .makeMultilib());
   // Use the hwasan+noexcept variant with HWASan and -fno-exceptions.
-  Multilibs.push_back(Multilib("hwasan+noexcept", {}, {}, 5)
+  Multilibs.push_back(MultilibBuilder("hwasan+noexcept", {}, {}, 5)
                           .flag("+fsanitize=hwaddress")
                           .flag("-fexceptions")
-                          .flag("+fno-exceptions"));
+                          .flag("+fno-exceptions")
+                          .makeMultilib());
   // Use Itanium C++ ABI for the compat multilib.
-  Multilibs.push_back(Multilib("compat", {}, {}, 6).flag("+fc++-abi=itanium"));
+  Multilibs.push_back(MultilibBuilder("compat", {}, {}, 6)
+                          .flag("+fc++-abi=itanium")
+                          .makeMultilib());
 
   Multilibs.FilterOut([&](const Multilib &M) {
     std::vector<std::string> RD = FilePaths(M);

diff  --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index c8006f3d8412c..3a69a2967462e 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -20,6 +20,7 @@
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/MultilibBuilder.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/Tool.h"
 #include "clang/Driver/ToolChain.h"
@@ -1045,38 +1046,34 @@ static bool isMSP430(llvm::Triple::ArchType Arch) {
   return Arch == llvm::Triple::msp430;
 }
 
-static Multilib makeMultilib(StringRef commonSuffix) {
-  return Multilib(commonSuffix, commonSuffix, commonSuffix);
-}
-
 static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
                                 FilterNonExistent &NonExistent,
                                 DetectedMultilibs &Result) {
   // Check for Code Sourcery toolchain multilibs
   MultilibSet CSMipsMultilibs;
   {
-    auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16");
+    auto MArchMips16 = MultilibBuilder("/mips16").flag("+m32").flag("+mips16");
 
     auto MArchMicroMips =
-        makeMultilib("/micromips").flag("+m32").flag("+mmicromips");
+        MultilibBuilder("/micromips").flag("+m32").flag("+mmicromips");
 
-    auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips");
+    auto MArchDefault = MultilibBuilder("").flag("-mips16").flag("-mmicromips");
 
-    auto UCLibc = makeMultilib("/uclibc").flag("+muclibc");
+    auto UCLibc = MultilibBuilder("/uclibc").flag("+muclibc");
 
-    auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float");
+    auto SoftFloat = MultilibBuilder("/soft-float").flag("+msoft-float");
 
-    auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008");
+    auto Nan2008 = MultilibBuilder("/nan2008").flag("+mnan=2008");
 
     auto DefaultFloat =
-        makeMultilib("").flag("-msoft-float").flag("-mnan=2008");
+        MultilibBuilder("").flag("-msoft-float").flag("-mnan=2008");
 
-    auto BigEndian = makeMultilib("").flag("+EB").flag("-EL");
+    auto BigEndian = MultilibBuilder("").flag("+EB").flag("-EL");
 
-    auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
+    auto LittleEndian = MultilibBuilder("/el").flag("+EL").flag("-EB");
 
     // Note that this one's osSuffix is ""
-    auto MAbi64 = makeMultilib("")
+    auto MAbi64 = MultilibBuilder("")
                       .gccSuffix("/64")
                       .includeSuffix("/64")
                       .flag("+mabi=n64")
@@ -1084,7 +1081,7 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
                       .flag("-m32");
 
     CSMipsMultilibs =
-        MultilibSet()
+        MultilibSetBuilder()
             .Either(MArchMips16, MArchMicroMips, MArchDefault)
             .Maybe(UCLibc)
             .Either(SoftFloat, Nan2008, DefaultFloat)
@@ -1094,6 +1091,7 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
             .Maybe(MAbi64)
             .FilterOut("/mips16.*/64")
             .FilterOut("/micromips.*/64")
+            .makeMultilibSet()
             .FilterOut(NonExistent)
             .setIncludeDirsCallback([](const Multilib &M) {
               std::vector<std::string> Dirs({"/include"});
@@ -1108,21 +1106,25 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
 
   MultilibSet DebianMipsMultilibs;
   {
-    Multilib MAbiN32 =
-        Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32");
+    MultilibBuilder MAbiN32 =
+        MultilibBuilder().gccSuffix("/n32").includeSuffix("/n32").flag(
+            "+mabi=n32");
 
-    Multilib M64 = Multilib()
-                       .gccSuffix("/64")
-                       .includeSuffix("/64")
-                       .flag("+m64")
-                       .flag("-m32")
-                       .flag("-mabi=n32");
+    MultilibBuilder M64 = MultilibBuilder()
+                              .gccSuffix("/64")
+                              .includeSuffix("/64")
+                              .flag("+m64")
+                              .flag("-m32")
+                              .flag("-mabi=n32");
 
-    Multilib M32 =
-        Multilib().gccSuffix("/32").flag("-m64").flag("+m32").flag("-mabi=n32");
+    MultilibBuilder M32 =
+        MultilibBuilder().gccSuffix("/32").flag("-m64").flag("+m32").flag(
+            "-mabi=n32");
 
-    DebianMipsMultilibs =
-        MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent);
+    DebianMipsMultilibs = MultilibSetBuilder()
+                              .Either(M32, M64, MAbiN32)
+                              .makeMultilibSet()
+                              .FilterOut(NonExistent);
   }
 
   // Sort candidates. Toolchain that best meets the directories tree goes first.
@@ -1147,25 +1149,32 @@ static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path,
                                      DetectedMultilibs &Result) {
 
   MultilibSet AndroidMipsMultilibs =
-      MultilibSet()
-          .Maybe(Multilib("/mips-r2").flag("+march=mips32r2"))
-          .Maybe(Multilib("/mips-r6").flag("+march=mips32r6"))
+      MultilibSetBuilder()
+          .Maybe(MultilibBuilder("/mips-r2", {}, {}).flag("+march=mips32r2"))
+          .Maybe(MultilibBuilder("/mips-r6", {}, {}).flag("+march=mips32r6"))
+          .makeMultilibSet()
           .FilterOut(NonExistent);
 
   MultilibSet AndroidMipselMultilibs =
-      MultilibSet()
-          .Either(Multilib().flag("+march=mips32"),
-                  Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"),
-                  Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6"))
+      MultilibSetBuilder()
+          .Either(MultilibBuilder().flag("+march=mips32"),
+                  MultilibBuilder("/mips-r2", "", "/mips-r2")
+                      .flag("+march=mips32r2"),
+                  MultilibBuilder("/mips-r6", "", "/mips-r6")
+                      .flag("+march=mips32r6"))
+          .makeMultilibSet()
           .FilterOut(NonExistent);
 
   MultilibSet AndroidMips64elMultilibs =
-      MultilibSet()
-          .Either(
-              Multilib().flag("+march=mips64r6"),
-              Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"),
-              Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"),
-              Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6"))
+      MultilibSetBuilder()
+          .Either(MultilibBuilder().flag("+march=mips64r6"),
+                  MultilibBuilder("/32/mips-r1", "", "/mips-r1")
+                      .flag("+march=mips32"),
+                  MultilibBuilder("/32/mips-r2", "", "/mips-r2")
+                      .flag("+march=mips32r2"),
+                  MultilibBuilder("/32/mips-r6", "", "/mips-r6")
+                      .flag("+march=mips32r6"))
+          .makeMultilibSet()
           .FilterOut(NonExistent);
 
   MultilibSet *MS = &AndroidMipsMultilibs;
@@ -1186,18 +1195,20 @@ static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags,
   // Musl toolchain multilibs
   MultilibSet MuslMipsMultilibs;
   {
-    auto MArchMipsR2 = makeMultilib("")
+    auto MArchMipsR2 = MultilibBuilder("")
                            .osSuffix("/mips-r2-hard-musl")
                            .flag("+EB")
                            .flag("-EL")
                            .flag("+march=mips32r2");
 
-    auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl")
+    auto MArchMipselR2 = MultilibBuilder("/mipsel-r2-hard-musl")
                              .flag("-EB")
                              .flag("+EL")
                              .flag("+march=mips32r2");
 
-    MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2);
+    MuslMipsMultilibs = MultilibSetBuilder()
+                            .Either(MArchMipsR2, MArchMipselR2)
+                            .makeMultilibSet();
 
     // Specify the callback that computes the include directories.
     MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) {
@@ -1218,48 +1229,49 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
   // CodeScape MTI toolchain v1.2 and early.
   MultilibSet MtiMipsMultilibsV1;
   {
-    auto MArchMips32 = makeMultilib("/mips32")
+    auto MArchMips32 = MultilibBuilder("/mips32")
                            .flag("+m32")
                            .flag("-m64")
                            .flag("-mmicromips")
                            .flag("+march=mips32");
 
-    auto MArchMicroMips = makeMultilib("/micromips")
+    auto MArchMicroMips = MultilibBuilder("/micromips")
                               .flag("+m32")
                               .flag("-m64")
                               .flag("+mmicromips");
 
-    auto MArchMips64r2 = makeMultilib("/mips64r2")
+    auto MArchMips64r2 = MultilibBuilder("/mips64r2")
                              .flag("-m32")
                              .flag("+m64")
                              .flag("+march=mips64r2");
 
-    auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag(
-        "-march=mips64r2");
+    auto MArchMips64 =
+        MultilibBuilder("/mips64").flag("-m32").flag("+m64").flag(
+            "-march=mips64r2");
 
-    auto MArchDefault = makeMultilib("")
+    auto MArchDefault = MultilibBuilder("")
                             .flag("+m32")
                             .flag("-m64")
                             .flag("-mmicromips")
                             .flag("+march=mips32r2");
 
-    auto Mips16 = makeMultilib("/mips16").flag("+mips16");
+    auto Mips16 = MultilibBuilder("/mips16").flag("+mips16");
 
-    auto UCLibc = makeMultilib("/uclibc").flag("+muclibc");
+    auto UCLibc = MultilibBuilder("/uclibc").flag("+muclibc");
 
     auto MAbi64 =
-        makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
+        MultilibBuilder("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
 
-    auto BigEndian = makeMultilib("").flag("+EB").flag("-EL");
+    auto BigEndian = MultilibBuilder("").flag("+EB").flag("-EL");
 
-    auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
+    auto LittleEndian = MultilibBuilder("/el").flag("+EL").flag("-EB");
 
-    auto SoftFloat = makeMultilib("/sof").flag("+msoft-float");
+    auto SoftFloat = MultilibBuilder("/sof").flag("+msoft-float");
 
-    auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008");
+    auto Nan2008 = MultilibBuilder("/nan2008").flag("+mnan=2008");
 
     MtiMipsMultilibsV1 =
-        MultilibSet()
+        MultilibSetBuilder()
             .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64,
                     MArchDefault)
             .Maybe(UCLibc)
@@ -1276,6 +1288,7 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
             .Maybe(SoftFloat)
             .Maybe(Nan2008)
             .FilterOut(".*sof/nan2008")
+            .makeMultilibSet()
             .FilterOut(NonExistent)
             .setIncludeDirsCallback([](const Multilib &M) {
               std::vector<std::string> Dirs({"/include"});
@@ -1290,80 +1303,87 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
   // CodeScape IMG toolchain starting from v1.3.
   MultilibSet MtiMipsMultilibsV2;
   {
-    auto BeHard = makeMultilib("/mips-r2-hard")
+    auto BeHard = MultilibBuilder("/mips-r2-hard")
                       .flag("+EB")
                       .flag("-msoft-float")
                       .flag("-mnan=2008")
                       .flag("-muclibc");
-    auto BeSoft = makeMultilib("/mips-r2-soft")
+    auto BeSoft = MultilibBuilder("/mips-r2-soft")
                       .flag("+EB")
                       .flag("+msoft-float")
                       .flag("-mnan=2008");
-    auto ElHard = makeMultilib("/mipsel-r2-hard")
+    auto ElHard = MultilibBuilder("/mipsel-r2-hard")
                       .flag("+EL")
                       .flag("-msoft-float")
                       .flag("-mnan=2008")
                       .flag("-muclibc");
-    auto ElSoft = makeMultilib("/mipsel-r2-soft")
+    auto ElSoft = MultilibBuilder("/mipsel-r2-soft")
                       .flag("+EL")
                       .flag("+msoft-float")
                       .flag("-mnan=2008")
                       .flag("-mmicromips");
-    auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008")
+    auto BeHardNan = MultilibBuilder("/mips-r2-hard-nan2008")
                          .flag("+EB")
                          .flag("-msoft-float")
                          .flag("+mnan=2008")
                          .flag("-muclibc");
-    auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008")
+    auto ElHardNan = MultilibBuilder("/mipsel-r2-hard-nan2008")
                          .flag("+EL")
                          .flag("-msoft-float")
                          .flag("+mnan=2008")
                          .flag("-muclibc")
                          .flag("-mmicromips");
-    auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc")
+    auto BeHardNanUclibc = MultilibBuilder("/mips-r2-hard-nan2008-uclibc")
                                .flag("+EB")
                                .flag("-msoft-float")
                                .flag("+mnan=2008")
                                .flag("+muclibc");
-    auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc")
+    auto ElHardNanUclibc = MultilibBuilder("/mipsel-r2-hard-nan2008-uclibc")
                                .flag("+EL")
                                .flag("-msoft-float")
                                .flag("+mnan=2008")
                                .flag("+muclibc");
-    auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc")
+    auto BeHardUclibc = MultilibBuilder("/mips-r2-hard-uclibc")
                             .flag("+EB")
                             .flag("-msoft-float")
                             .flag("-mnan=2008")
                             .flag("+muclibc");
-    auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc")
+    auto ElHardUclibc = MultilibBuilder("/mipsel-r2-hard-uclibc")
                             .flag("+EL")
                             .flag("-msoft-float")
                             .flag("-mnan=2008")
                             .flag("+muclibc");
-    auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008")
+    auto ElMicroHardNan = MultilibBuilder("/micromipsel-r2-hard-nan2008")
                               .flag("+EL")
                               .flag("-msoft-float")
                               .flag("+mnan=2008")
                               .flag("+mmicromips");
-    auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft")
+    auto ElMicroSoft = MultilibBuilder("/micromipsel-r2-soft")
                            .flag("+EL")
                            .flag("+msoft-float")
                            .flag("-mnan=2008")
                            .flag("+mmicromips");
 
-    auto O32 =
-        makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64");
-    auto N32 =
-        makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64");
-    auto N64 =
-        makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64");
+    auto O32 = MultilibBuilder("/lib")
+                   .osSuffix("")
+                   .flag("-mabi=n32")
+                   .flag("-mabi=n64");
+    auto N32 = MultilibBuilder("/lib32")
+                   .osSuffix("")
+                   .flag("+mabi=n32")
+                   .flag("-mabi=n64");
+    auto N64 = MultilibBuilder("/lib64")
+                   .osSuffix("")
+                   .flag("-mabi=n32")
+                   .flag("+mabi=n64");
 
     MtiMipsMultilibsV2 =
-        MultilibSet()
+        MultilibSetBuilder()
             .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan,
                      BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc,
                      ElHardUclibc, ElMicroHardNan, ElMicroSoft})
             .Either(O32, N32, N64)
+            .makeMultilibSet()
             .FilterOut(NonExistent)
             .setIncludeDirsCallback([](const Multilib &M) {
               return std::vector<std::string>({"/../../../../sysroot" +
@@ -1390,18 +1410,19 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
   // CodeScape IMG toolchain v1.2 and early.
   MultilibSet ImgMultilibsV1;
   {
-    auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32");
+    auto Mips64r6 = MultilibBuilder("/mips64r6").flag("+m64").flag("-m32");
 
-    auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
+    auto LittleEndian = MultilibBuilder("/el").flag("+EL").flag("-EB");
 
     auto MAbi64 =
-        makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
+        MultilibBuilder("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
 
     ImgMultilibsV1 =
-        MultilibSet()
+        MultilibSetBuilder()
             .Maybe(Mips64r6)
             .Maybe(MAbi64)
             .Maybe(LittleEndian)
+            .makeMultilibSet()
             .FilterOut(NonExistent)
             .setIncludeDirsCallback([](const Multilib &M) {
               return std::vector<std::string>(
@@ -1412,51 +1433,58 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
   // CodeScape IMG toolchain starting from v1.3.
   MultilibSet ImgMultilibsV2;
   {
-    auto BeHard = makeMultilib("/mips-r6-hard")
+    auto BeHard = MultilibBuilder("/mips-r6-hard")
                       .flag("+EB")
                       .flag("-msoft-float")
                       .flag("-mmicromips");
-    auto BeSoft = makeMultilib("/mips-r6-soft")
+    auto BeSoft = MultilibBuilder("/mips-r6-soft")
                       .flag("+EB")
                       .flag("+msoft-float")
                       .flag("-mmicromips");
-    auto ElHard = makeMultilib("/mipsel-r6-hard")
+    auto ElHard = MultilibBuilder("/mipsel-r6-hard")
                       .flag("+EL")
                       .flag("-msoft-float")
                       .flag("-mmicromips");
-    auto ElSoft = makeMultilib("/mipsel-r6-soft")
+    auto ElSoft = MultilibBuilder("/mipsel-r6-soft")
                       .flag("+EL")
                       .flag("+msoft-float")
                       .flag("-mmicromips");
-    auto BeMicroHard = makeMultilib("/micromips-r6-hard")
+    auto BeMicroHard = MultilibBuilder("/micromips-r6-hard")
                            .flag("+EB")
                            .flag("-msoft-float")
                            .flag("+mmicromips");
-    auto BeMicroSoft = makeMultilib("/micromips-r6-soft")
+    auto BeMicroSoft = MultilibBuilder("/micromips-r6-soft")
                            .flag("+EB")
                            .flag("+msoft-float")
                            .flag("+mmicromips");
-    auto ElMicroHard = makeMultilib("/micromipsel-r6-hard")
+    auto ElMicroHard = MultilibBuilder("/micromipsel-r6-hard")
                            .flag("+EL")
                            .flag("-msoft-float")
                            .flag("+mmicromips");
-    auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft")
+    auto ElMicroSoft = MultilibBuilder("/micromipsel-r6-soft")
                            .flag("+EL")
                            .flag("+msoft-float")
                            .flag("+mmicromips");
 
-    auto O32 =
-        makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64");
-    auto N32 =
-        makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64");
-    auto N64 =
-        makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64");
+    auto O32 = MultilibBuilder("/lib")
+                   .osSuffix("")
+                   .flag("-mabi=n32")
+                   .flag("-mabi=n64");
+    auto N32 = MultilibBuilder("/lib32")
+                   .osSuffix("")
+                   .flag("+mabi=n32")
+                   .flag("-mabi=n64");
+    auto N64 = MultilibBuilder("/lib64")
+                   .osSuffix("")
+                   .flag("-mabi=n32")
+                   .flag("+mabi=n64");
 
     ImgMultilibsV2 =
-        MultilibSet()
+        MultilibSetBuilder()
             .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft,
                      ElMicroHard, ElMicroSoft})
             .Either(O32, N32, N64)
+            .makeMultilibSet()
             .FilterOut(NonExistent)
             .setIncludeDirsCallback([](const Multilib &M) {
               return std::vector<std::string>({"/../../../../sysroot" +
@@ -1556,22 +1584,19 @@ static void findAndroidArmMultilibs(const Driver &D,
                                     DetectedMultilibs &Result) {
   // Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb.
   FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
-  Multilib ArmV7Multilib = makeMultilib("/armv7-a")
-                               .flag("+march=armv7-a")
-                               .flag("-mthumb");
-  Multilib ThumbMultilib = makeMultilib("/thumb")
-                               .flag("-march=armv7-a")
-                               .flag("+mthumb");
-  Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb")
-                               .flag("+march=armv7-a")
-                               .flag("+mthumb");
-  Multilib DefaultMultilib = makeMultilib("")
-                               .flag("-march=armv7-a")
-                               .flag("-mthumb");
+  MultilibBuilder ArmV7Multilib =
+      MultilibBuilder("/armv7-a").flag("+march=armv7-a").flag("-mthumb");
+  MultilibBuilder ThumbMultilib =
+      MultilibBuilder("/thumb").flag("-march=armv7-a").flag("+mthumb");
+  MultilibBuilder ArmV7ThumbMultilib =
+      MultilibBuilder("/armv7-a/thumb").flag("+march=armv7-a").flag("+mthumb");
+  MultilibBuilder DefaultMultilib =
+      MultilibBuilder("").flag("-march=armv7-a").flag("-mthumb");
   MultilibSet AndroidArmMultilibs =
-      MultilibSet()
-          .Either(ThumbMultilib, ArmV7Multilib,
-                  ArmV7ThumbMultilib, DefaultMultilib)
+      MultilibSetBuilder()
+          .Either(ThumbMultilib, ArmV7Multilib, ArmV7ThumbMultilib,
+                  DefaultMultilib)
+          .makeMultilibSet()
           .FilterOut(NonExistent);
 
   Multilib::flags_list Flags;
@@ -1597,15 +1622,17 @@ static bool findMSP430Multilibs(const Driver &D,
                                 StringRef Path, const ArgList &Args,
                                 DetectedMultilibs &Result) {
   FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
-  Multilib WithoutExceptions = makeMultilib("/430").flag("-exceptions");
-  Multilib WithExceptions = makeMultilib("/430/exceptions").flag("+exceptions");
+  MultilibBuilder WithoutExceptions =
+      MultilibBuilder("/430").flag("-exceptions");
+  MultilibBuilder WithExceptions =
+      MultilibBuilder("/430/exceptions").flag("+exceptions");
 
   // FIXME: when clang starts to support msp430x ISA additional logic
   // to select between multilib must be implemented
-  // Multilib MSP430xMultilib = makeMultilib("/large");
+  // MultilibBuilder MSP430xMultilib = MultilibBuilder("/large");
 
-  Result.Multilibs.push_back(WithoutExceptions);
-  Result.Multilibs.push_back(WithExceptions);
+  Result.Multilibs.push_back(WithoutExceptions.makeMultilib());
+  Result.Multilibs.push_back(WithExceptions.makeMultilib());
   Result.Multilibs.FilterOut(NonExistent);
 
   Multilib::flags_list Flags;
@@ -1653,28 +1680,29 @@ static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
     isBigEndian = !A->getOption().matches(options::OPT_mlittle_endian);
   addMultilibFlag(isBigEndian, "EB", Flags);
 
-  auto HardFloat = makeMultilib("/hard-fp").flag("+hard-fp");
-  auto SoftFpFloat = makeMultilib("/soft-fp").flag("+soft-fp");
-  auto SoftFloat = makeMultilib("").flag("+soft");
-  auto Arch801 = makeMultilib("/ck801").flag("+march=ck801");
-  auto Arch802 = makeMultilib("/ck802").flag("+march=ck802");
-  auto Arch803 = makeMultilib("/ck803").flag("+march=ck803");
+  auto HardFloat = MultilibBuilder("/hard-fp").flag("+hard-fp");
+  auto SoftFpFloat = MultilibBuilder("/soft-fp").flag("+soft-fp");
+  auto SoftFloat = MultilibBuilder("").flag("+soft");
+  auto Arch801 = MultilibBuilder("/ck801").flag("+march=ck801");
+  auto Arch802 = MultilibBuilder("/ck802").flag("+march=ck802");
+  auto Arch803 = MultilibBuilder("/ck803").flag("+march=ck803");
   // CK804 use the same library as CK803
-  auto Arch804 = makeMultilib("/ck803").flag("+march=ck804");
-  auto Arch805 = makeMultilib("/ck805").flag("+march=ck805");
-  auto Arch807 = makeMultilib("/ck807").flag("+march=ck807");
-  auto Arch810 = makeMultilib("").flag("+march=ck810");
-  auto Arch810v = makeMultilib("/ck810v").flag("+march=ck810v");
-  auto Arch860 = makeMultilib("/ck860").flag("+march=ck860");
-  auto Arch860v = makeMultilib("/ck860v").flag("+march=ck860v");
-  auto BigEndian = makeMultilib("/big").flag("+EB");
+  auto Arch804 = MultilibBuilder("/ck803").flag("+march=ck804");
+  auto Arch805 = MultilibBuilder("/ck805").flag("+march=ck805");
+  auto Arch807 = MultilibBuilder("/ck807").flag("+march=ck807");
+  auto Arch810 = MultilibBuilder("").flag("+march=ck810");
+  auto Arch810v = MultilibBuilder("/ck810v").flag("+march=ck810v");
+  auto Arch860 = MultilibBuilder("/ck860").flag("+march=ck860");
+  auto Arch860v = MultilibBuilder("/ck860v").flag("+march=ck860v");
+  auto BigEndian = MultilibBuilder("/big").flag("+EB");
 
   MultilibSet CSKYMultilibs =
-      MultilibSet()
+      MultilibSetBuilder()
           .Maybe(BigEndian)
           .Either({Arch801, Arch802, Arch803, Arch804, Arch805, Arch807,
                    Arch810, Arch810v, Arch860, Arch860v})
           .Either(HardFloat, SoftFpFloat, SoftFloat)
+          .makeMultilibSet()
           .FilterOut(NonExistent);
 
   if (CSKYMultilibs.select(Flags, Result.SelectedMultilib))
@@ -1697,17 +1725,19 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
       {"rv32imac", "ilp32"},  {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"},
       {"rv64imafdc", "lp64d"}};
 
-  std::vector<Multilib> Ms;
+  std::vector<MultilibBuilder> Ms;
   for (auto Element : RISCVMultilibSet) {
     // multilib path rule is ${march}/${mabi}
     Ms.emplace_back(
-        makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str())
+        MultilibBuilder(
+            (Twine(Element.march) + "/" + Twine(Element.mabi)).str())
             .flag(Twine("+march=", Element.march).str())
             .flag(Twine("+mabi=", Element.mabi).str()));
   }
   MultilibSet RISCVMultilibs =
-      MultilibSet()
-          .Either(ArrayRef<Multilib>(Ms))
+      MultilibSetBuilder()
+          .Either(Ms)
+          .makeMultilibSet()
           .FilterOut(NonExistent)
           .setFilePathsCallback([](const Multilib &M) {
             return std::vector<std::string>(
@@ -1716,7 +1746,6 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
                  "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()});
           });
 
-
   Multilib::flags_list Flags;
   llvm::StringSet<> Added_ABIs;
   StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple);
@@ -1742,17 +1771,22 @@ static void findRISCVMultilibs(const Driver &D,
     return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result);
 
   FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
-  Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32");
-  Multilib Ilp32f =
-      makeMultilib("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f");
-  Multilib Ilp32d =
-      makeMultilib("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d");
-  Multilib Lp64 = makeMultilib("lib64/lp64").flag("+m64").flag("+mabi=lp64");
-  Multilib Lp64f = makeMultilib("lib64/lp64f").flag("+m64").flag("+mabi=lp64f");
-  Multilib Lp64d = makeMultilib("lib64/lp64d").flag("+m64").flag("+mabi=lp64d");
+  MultilibBuilder Ilp32 =
+      MultilibBuilder("lib32/ilp32").flag("+m32").flag("+mabi=ilp32");
+  MultilibBuilder Ilp32f =
+      MultilibBuilder("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f");
+  MultilibBuilder Ilp32d =
+      MultilibBuilder("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d");
+  MultilibBuilder Lp64 =
+      MultilibBuilder("lib64/lp64").flag("+m64").flag("+mabi=lp64");
+  MultilibBuilder Lp64f =
+      MultilibBuilder("lib64/lp64f").flag("+m64").flag("+mabi=lp64f");
+  MultilibBuilder Lp64d =
+      MultilibBuilder("lib64/lp64d").flag("+m64").flag("+mabi=lp64d");
   MultilibSet RISCVMultilibs =
-      MultilibSet()
+      MultilibSetBuilder()
           .Either({Ilp32, Ilp32f, Ilp32d, Lp64, Lp64f, Lp64d})
+          .makeMultilibSet()
           .FilterOut(NonExistent);
 
   Multilib::flags_list Flags;
@@ -1777,7 +1811,7 @@ static bool findBiarchMultilibs(const Driver &D,
                                 StringRef Path, const ArgList &Args,
                                 bool NeedsBiarchSuffix,
                                 DetectedMultilibs &Result) {
-  Multilib Default;
+  MultilibBuilder DefaultBuilder;
 
   // Some versions of SUSE and Fedora on ppc64 put 32-bit libs
   // in what would normally be GCCInstallPath and put the 64-bit
@@ -1803,24 +1837,27 @@ static bool findBiarchMultilibs(const Driver &D,
     }
   }
 
-  Multilib Alt64 = Multilib()
+  Multilib Alt64 = MultilibBuilder()
                        .gccSuffix(Suff64)
                        .includeSuffix(Suff64)
                        .flag("-m32")
                        .flag("+m64")
-                       .flag("-mx32");
-  Multilib Alt32 = Multilib()
+                       .flag("-mx32")
+                       .makeMultilib();
+  Multilib Alt32 = MultilibBuilder()
                        .gccSuffix("/32")
                        .includeSuffix("/32")
                        .flag("+m32")
                        .flag("-m64")
-                       .flag("-mx32");
-  Multilib Altx32 = Multilib()
+                       .flag("-mx32")
+                       .makeMultilib();
+  Multilib Altx32 = MultilibBuilder()
                         .gccSuffix("/x32")
                         .includeSuffix("/x32")
                         .flag("-m32")
                         .flag("-m64")
-                        .flag("+mx32");
+                        .flag("+mx32")
+                        .makeMultilib();
 
   // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a.
   FilterNonExistent NonExistent(
@@ -1846,14 +1883,16 @@ static bool findBiarchMultilibs(const Driver &D,
   }
 
   if (Want == WANT32)
-    Default.flag("+m32").flag("-m64").flag("-mx32");
+    DefaultBuilder.flag("+m32").flag("-m64").flag("-mx32");
   else if (Want == WANT64)
-    Default.flag("-m32").flag("+m64").flag("-mx32");
+    DefaultBuilder.flag("-m32").flag("+m64").flag("-mx32");
   else if (Want == WANTX32)
-    Default.flag("-m32").flag("-m64").flag("+mx32");
+    DefaultBuilder.flag("-m32").flag("-m64").flag("+mx32");
   else
     return false;
 
+  Multilib Default = DefaultBuilder.makeMultilib();
+
   Result.Multilibs.push_back(Default);
   Result.Multilibs.push_back(Alt64);
   Result.Multilibs.push_back(Alt32);

diff  --git a/clang/unittests/Driver/CMakeLists.txt b/clang/unittests/Driver/CMakeLists.txt
index 1de0151cc41ce..e37c158d7137a 100644
--- a/clang/unittests/Driver/CMakeLists.txt
+++ b/clang/unittests/Driver/CMakeLists.txt
@@ -11,6 +11,7 @@ add_clang_unittest(ClangDriverTests
   DXCModeTest.cpp
   ToolChainTest.cpp
   ModuleCacheTest.cpp
+  MultilibBuilderTest.cpp
   MultilibTest.cpp
   SanitizerArgsTest.cpp
   )

diff  --git a/clang/unittests/Driver/MultilibBuilderTest.cpp b/clang/unittests/Driver/MultilibBuilderTest.cpp
new file mode 100644
index 0000000000000..45ef4992d3f78
--- /dev/null
+++ b/clang/unittests/Driver/MultilibBuilderTest.cpp
@@ -0,0 +1,209 @@
+//===- unittests/Driver/MultilibBuilderTest.cpp --- MultilibBuilder 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 MultilibBuilder and MultilibSetBuilder
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/MultilibBuilder.h"
+#include "../../lib/Driver/ToolChains/CommonArgs.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "gtest/gtest.h"
+
+using llvm::is_contained;
+using namespace clang;
+using namespace driver;
+
+TEST(MultilibBuilderTest, MultilibValidity) {
+
+  ASSERT_TRUE(MultilibBuilder().isValid()) << "Empty multilib is not valid";
+
+  ASSERT_TRUE(MultilibBuilder().flag("+foo").isValid())
+      << "Single indicative flag is not valid";
+
+  ASSERT_TRUE(MultilibBuilder().flag("-foo").isValid())
+      << "Single contraindicative flag is not valid";
+
+  ASSERT_FALSE(MultilibBuilder().flag("+foo").flag("-foo").isValid())
+      << "Conflicting flags should invalidate the Multilib";
+
+  ASSERT_TRUE(MultilibBuilder().flag("+foo").flag("+foo").isValid())
+      << "Multilib should be valid even if it has the same flag "
+         "twice";
+
+  ASSERT_TRUE(MultilibBuilder().flag("+foo").flag("-foobar").isValid())
+      << "Seemingly conflicting prefixes shouldn't actually conflict";
+}
+
+TEST(MultilibBuilderTest, Construction1) {
+  MultilibBuilder M("gcc64", "os64", "inc64");
+  ASSERT_TRUE(M.gccSuffix() == "/gcc64");
+  ASSERT_TRUE(M.osSuffix() == "/os64");
+  ASSERT_TRUE(M.includeSuffix() == "/inc64");
+}
+
+TEST(MultilibBuilderTest, Construction3) {
+  MultilibBuilder M = MultilibBuilder().flag("+f1").flag("+f2").flag("-f3");
+  for (const std::string &A : M.flags()) {
+    ASSERT_TRUE(llvm::StringSwitch<bool>(A)
+                    .Cases("+f1", "+f2", "-f3", true)
+                    .Default(false));
+  }
+}
+
+TEST(MultilibBuilderTest, SetConstruction1) {
+  // Single maybe
+  MultilibSet MS = MultilibSetBuilder()
+                       .Maybe(MultilibBuilder("64").flag("+m64"))
+                       .makeMultilibSet();
+  ASSERT_TRUE(MS.size() == 2);
+  for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
+    if (I->gccSuffix() == "/64")
+      ASSERT_TRUE(*I->flags().begin() == "+m64");
+    else if (I->gccSuffix() == "")
+      ASSERT_TRUE(*I->flags().begin() == "-m64");
+    else
+      FAIL() << "Unrecognized gccSufix: " << I->gccSuffix();
+  }
+}
+
+TEST(MultilibBuilderTest, SetConstruction2) {
+  // Double maybe
+  MultilibSet MS = MultilibSetBuilder()
+                       .Maybe(MultilibBuilder("sof").flag("+sof"))
+                       .Maybe(MultilibBuilder("el").flag("+EL"))
+                       .makeMultilibSet();
+  ASSERT_TRUE(MS.size() == 4);
+  for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
+    ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
+                    .Cases("", "/sof", "/el", "/sof/el", true)
+                    .Default(false))
+        << "Multilib " << *I << " wasn't expected";
+    ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
+                    .Case("", is_contained(I->flags(), "-sof"))
+                    .Case("/sof", is_contained(I->flags(), "+sof"))
+                    .Case("/el", is_contained(I->flags(), "-sof"))
+                    .Case("/sof/el", is_contained(I->flags(), "+sof"))
+                    .Default(false))
+        << "Multilib " << *I << " didn't have the appropriate {+,-}sof flag";
+    ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
+                    .Case("", is_contained(I->flags(), "-EL"))
+                    .Case("/sof", is_contained(I->flags(), "-EL"))
+                    .Case("/el", is_contained(I->flags(), "+EL"))
+                    .Case("/sof/el", is_contained(I->flags(), "+EL"))
+                    .Default(false))
+        << "Multilib " << *I << " didn't have the appropriate {+,-}EL flag";
+  }
+}
+
+TEST(MultilibBuilderTest, SetRegexFilter) {
+  MultilibSetBuilder MB;
+  MB.Maybe(MultilibBuilder("one"))
+      .Maybe(MultilibBuilder("two"))
+      .Maybe(MultilibBuilder("three"))
+      .makeMultilibSet();
+  MultilibSet MS = MB.makeMultilibSet();
+  ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2)
+      << "Size before filter was incorrect. Contents:\n"
+      << MS;
+  MB.FilterOut("/one/two/three");
+  MS = MB.makeMultilibSet();
+  ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2 - 1)
+      << "Size after filter was incorrect. Contents:\n"
+      << MS;
+  for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
+    ASSERT_TRUE(I->gccSuffix() != "/one/two/three")
+        << "The filter should have removed " << *I;
+  }
+}
+
+TEST(MultilibBuilderTest, SetFilterObject) {
+  MultilibSet MS = MultilibSetBuilder()
+                       .Maybe(MultilibBuilder("orange"))
+                       .Maybe(MultilibBuilder("pear"))
+                       .Maybe(MultilibBuilder("plum"))
+                       .makeMultilibSet();
+  ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* pear */ + 1 /* plum */ +
+                                1 /* pear/plum */ + 1 /* orange */ +
+                                1 /* orange/pear */ + 1 /* orange/plum */ +
+                                1 /* orange/pear/plum */)
+      << "Size before filter was incorrect. Contents:\n"
+      << MS;
+  MS.FilterOut([](const Multilib &M) {
+    return StringRef(M.gccSuffix()).startswith("/p");
+  });
+  ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* orange */ +
+                                1 /* orange/pear */ + 1 /* orange/plum */ +
+                                1 /* orange/pear/plum */)
+      << "Size after filter was incorrect. Contents:\n"
+      << MS;
+  for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
+    ASSERT_FALSE(StringRef(I->gccSuffix()).startswith("/p"))
+        << "The filter should have removed " << *I;
+  }
+}
+
+TEST(MultilibBuilderTest, SetSelection1) {
+  MultilibSet MS1 = MultilibSetBuilder()
+                        .Maybe(MultilibBuilder("64").flag("+m64"))
+                        .makeMultilibSet();
+
+  Multilib::flags_list FlagM64 = {"+m64"};
+  Multilib SelectionM64;
+  ASSERT_TRUE(MS1.select(FlagM64, SelectionM64))
+      << "Flag set was {\"+m64\"}, but selection not found";
+  ASSERT_TRUE(SelectionM64.gccSuffix() == "/64")
+      << "Selection picked " << SelectionM64 << " which was not expected";
+
+  Multilib::flags_list FlagNoM64 = {"-m64"};
+  Multilib SelectionNoM64;
+  ASSERT_TRUE(MS1.select(FlagNoM64, SelectionNoM64))
+      << "Flag set was {\"-m64\"}, but selection not found";
+  ASSERT_TRUE(SelectionNoM64.gccSuffix() == "")
+      << "Selection picked " << SelectionNoM64 << " which was not expected";
+}
+
+TEST(MultilibBuilderTest, SetSelection2) {
+  MultilibSet MS2 = MultilibSetBuilder()
+                        .Maybe(MultilibBuilder("el").flag("+EL"))
+                        .Maybe(MultilibBuilder("sf").flag("+SF"))
+                        .makeMultilibSet();
+
+  for (unsigned I = 0; I < 4; ++I) {
+    bool IsEL = I & 0x1;
+    bool IsSF = I & 0x2;
+    Multilib::flags_list Flags;
+    if (IsEL)
+      Flags.push_back("+EL");
+    else
+      Flags.push_back("-EL");
+
+    if (IsSF)
+      Flags.push_back("+SF");
+    else
+      Flags.push_back("-SF");
+
+    Multilib Selection;
+    ASSERT_TRUE(MS2.select(Flags, Selection))
+        << "Selection failed for " << (IsEL ? "+EL" : "-EL") << " "
+        << (IsSF ? "+SF" : "-SF");
+
+    std::string Suffix;
+    if (IsEL)
+      Suffix += "/el";
+    if (IsSF)
+      Suffix += "/sf";
+
+    ASSERT_EQ(Selection.gccSuffix(), Suffix)
+        << "Selection picked " << Selection << " which was not expected ";
+  }
+}

diff  --git a/clang/unittests/Driver/MultilibTest.cpp b/clang/unittests/Driver/MultilibTest.cpp
index 0731c81d9f554..2e729a5051734 100644
--- a/clang/unittests/Driver/MultilibTest.cpp
+++ b/clang/unittests/Driver/MultilibTest.cpp
@@ -11,34 +11,17 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Driver/Multilib.h"
+#include "../../lib/Driver/ToolChains/CommonArgs.h"
 #include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/SourceMgr.h"
 #include "gtest/gtest.h"
 
 using namespace clang::driver;
 using namespace clang;
 
-TEST(MultilibTest, MultilibValidity) {
-
-  ASSERT_TRUE(Multilib().isValid()) << "Empty multilib is not valid";
-
-  ASSERT_TRUE(Multilib().flag("+foo").isValid())
-      << "Single indicative flag is not valid";
-
-  ASSERT_TRUE(Multilib().flag("-foo").isValid())
-      << "Single contraindicative flag is not valid";
-
-  ASSERT_FALSE(Multilib().flag("+foo").flag("-foo").isValid())
-      << "Conflicting flags should invalidate the Multilib";
-
-  ASSERT_TRUE(Multilib().flag("+foo").flag("+foo").isValid())
-      << "Multilib should be valid even if it has the same flag twice";
-
-  ASSERT_TRUE(Multilib().flag("+foo").flag("-foobar").isValid())
-      << "Seemingly conflicting prefixes shouldn't actually conflict";
-}
-
 TEST(MultilibTest, OpEqReflexivity1) {
   Multilib M;
   ASSERT_TRUE(M == M) << "Multilib::operator==() is not reflexive";
@@ -50,40 +33,28 @@ TEST(MultilibTest, OpEqReflexivity2) {
 }
 
 TEST(MultilibTest, OpEqReflexivity3) {
-  Multilib M1, M2;
-  M1.flag("+foo");
-  M2.flag("+foo");
+  Multilib M1({}, {}, {}, 0, {"+foo"});
+  Multilib M2({}, {}, {}, 0, {"+foo"});
   ASSERT_TRUE(M1 == M2) << "Multilibs with the same flag should be the same";
 }
 
 TEST(MultilibTest, OpEqInequivalence1) {
-  Multilib M1, M2;
-  M1.flag("+foo");
-  M2.flag("-foo");
+  Multilib M1({}, {}, {}, 0, {"+foo"});
+  Multilib M2({}, {}, {}, 0, {"-foo"});
   ASSERT_FALSE(M1 == M2) << "Multilibs with conflicting flags are not the same";
   ASSERT_FALSE(M2 == M1)
       << "Multilibs with conflicting flags are not the same (commuted)";
 }
 
 TEST(MultilibTest, OpEqInequivalence2) {
-  Multilib M1, M2;
-  M2.flag("+foo");
+  Multilib M1;
+  Multilib M2({}, {}, {}, 0, {"+foo"});
   ASSERT_FALSE(M1 == M2) << "Flags make Multilibs 
diff erent";
 }
 
-TEST(MultilibTest, OpEqEquivalence1) {
-  Multilib M1, M2;
-  M1.flag("+foo");
-  M2.flag("+foo").flag("+foo");
-  ASSERT_TRUE(M1 == M2) << "Flag duplication shouldn't affect equivalence";
-  ASSERT_TRUE(M2 == M1)
-      << "Flag duplication shouldn't affect equivalence (commuted)";
-}
-
 TEST(MultilibTest, OpEqEquivalence2) {
-  Multilib M1("64");
-  Multilib M2;
-  M2.gccSuffix("/64");
+  Multilib M1("/64");
+  Multilib M2("/64");
   ASSERT_TRUE(M1 == M2)
       << "Constructor argument must match Multilib::gccSuffix()";
   ASSERT_TRUE(M2 == M1)
@@ -91,9 +62,8 @@ TEST(MultilibTest, OpEqEquivalence2) {
 }
 
 TEST(MultilibTest, OpEqEquivalence3) {
-  Multilib M1("", "32");
-  Multilib M2;
-  M2.osSuffix("/32");
+  Multilib M1("", "/32");
+  Multilib M2("", "/32");
   ASSERT_TRUE(M1 == M2)
       << "Constructor argument must match Multilib::osSuffix()";
   ASSERT_TRUE(M2 == M1)
@@ -101,9 +71,8 @@ TEST(MultilibTest, OpEqEquivalence3) {
 }
 
 TEST(MultilibTest, OpEqEquivalence4) {
-  Multilib M1("", "", "16");
-  Multilib M2;
-  M2.includeSuffix("/16");
+  Multilib M1("", "", "/16");
+  Multilib M2("", "", "/16");
   ASSERT_TRUE(M1 == M2)
       << "Constructor argument must match Multilib::includeSuffix()";
   ASSERT_TRUE(M2 == M1)
@@ -111,31 +80,31 @@ TEST(MultilibTest, OpEqEquivalence4) {
 }
 
 TEST(MultilibTest, OpEqInequivalence3) {
-  Multilib M1("foo");
-  Multilib M2("bar");
+  Multilib M1("/foo");
+  Multilib M2("/bar");
   ASSERT_FALSE(M1 == M2) << "Differing gccSuffixes should be 
diff erent";
   ASSERT_FALSE(M2 == M1)
       << "Differing gccSuffixes should be 
diff erent (commuted)";
 }
 
 TEST(MultilibTest, OpEqInequivalence4) {
-  Multilib M1("", "foo");
-  Multilib M2("", "bar");
+  Multilib M1("", "/foo");
+  Multilib M2("", "/bar");
   ASSERT_FALSE(M1 == M2) << "Differing osSuffixes should be 
diff erent";
   ASSERT_FALSE(M2 == M1)
       << "Differing osSuffixes should be 
diff erent (commuted)";
 }
 
 TEST(MultilibTest, OpEqInequivalence5) {
-  Multilib M1("", "", "foo");
-  Multilib M2("", "", "bar");
+  Multilib M1("", "", "/foo");
+  Multilib M2("", "", "/bar");
   ASSERT_FALSE(M1 == M2) << "Differing includeSuffixes should be 
diff erent";
   ASSERT_FALSE(M2 == M1)
       << "Differing includeSuffixes should be 
diff erent (commuted)";
 }
 
 TEST(MultilibTest, Construction1) {
-  Multilib M("gcc64", "os64", "inc64");
+  Multilib M("/gcc64", "/os64", "/inc64");
   ASSERT_TRUE(M.gccSuffix() == "/gcc64");
   ASSERT_TRUE(M.osSuffix() == "/os64");
   ASSERT_TRUE(M.includeSuffix() == "/inc64");
@@ -155,7 +124,7 @@ TEST(MultilibTest, Construction2) {
 }
 
 TEST(MultilibTest, Construction3) {
-  Multilib M = Multilib().flag("+f1").flag("+f2").flag("-f3");
+  Multilib M({}, {}, {}, 0, {"+f1", "+f2", "-f3"});
   for (Multilib::flags_list::const_iterator I = M.flags().begin(),
                                             E = M.flags().end();
        I != E; ++I) {
@@ -165,208 +134,32 @@ TEST(MultilibTest, Construction3) {
   }
 }
 
-static bool hasFlag(const Multilib &M, StringRef Flag) {
-  for (Multilib::flags_list::const_iterator I = M.flags().begin(),
-                                            E = M.flags().end();
-       I != E; ++I) {
-    if (*I == Flag)
-      return true;
-    else if (StringRef(*I).substr(1) == Flag.substr(1))
-      return false;
-  }
-  return false;
-}
-
-TEST(MultilibTest, SetConstruction1) {
-  // Single maybe
-  MultilibSet MS;
-  ASSERT_TRUE(MS.size() == 0);
-  MS.Maybe(Multilib("64").flag("+m64"));
-  ASSERT_TRUE(MS.size() == 2);
-  for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
-    if (I->gccSuffix() == "/64")
-      ASSERT_TRUE(I->flags()[0] == "+m64");
-    else if (I->gccSuffix() == "")
-      ASSERT_TRUE(I->flags()[0] == "-m64");
-    else
-      FAIL() << "Unrecognized gccSufix: " << I->gccSuffix();
-  }
-}
-
-TEST(MultilibTest, SetConstruction2) {
-  // Double maybe
-  MultilibSet MS;
-  MS.Maybe(Multilib("sof").flag("+sof"));
-  MS.Maybe(Multilib("el").flag("+EL"));
-  ASSERT_TRUE(MS.size() == 4);
-  for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
-    ASSERT_TRUE(I->isValid()) << "Multilb " << *I << " should be valid";
-    ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
-                    .Cases("", "/sof", "/el", "/sof/el", true)
-                    .Default(false))
-        << "Multilib " << *I << " wasn't expected";
-    ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
-                    .Case("", hasFlag(*I, "-sof"))
-                    .Case("/sof", hasFlag(*I, "+sof"))
-                    .Case("/el", hasFlag(*I, "-sof"))
-                    .Case("/sof/el", hasFlag(*I, "+sof"))
-                    .Default(false))
-        << "Multilib " << *I << " didn't have the appropriate {+,-}sof flag";
-    ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
-                    .Case("", hasFlag(*I, "-EL"))
-                    .Case("/sof", hasFlag(*I, "-EL"))
-                    .Case("/el", hasFlag(*I, "+EL"))
-                    .Case("/sof/el", hasFlag(*I, "+EL"))
-                    .Default(false))
-        << "Multilib " << *I << " didn't have the appropriate {+,-}EL flag";
-  }
-}
-
 TEST(MultilibTest, SetPushback) {
-  MultilibSet MS;
-  MS.push_back(Multilib("one"));
-  MS.push_back(Multilib("two"));
+  MultilibSet MS({
+      Multilib("/one"),
+      Multilib("/two"),
+  });
   ASSERT_TRUE(MS.size() == 2);
   for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
     ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
                     .Cases("/one", "/two", true)
                     .Default(false));
   }
-  MS.clear();
-  ASSERT_TRUE(MS.size() == 0);
-}
-
-TEST(MultilibTest, SetRegexFilter) {
-  MultilibSet MS;
-  MS.Maybe(Multilib("one"));
-  MS.Maybe(Multilib("two"));
-  MS.Maybe(Multilib("three"));
-  ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2)
-      << "Size before filter was incorrect. Contents:\n" << MS;
-  MS.FilterOut("/one/two/three");
-  ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2 - 1)
-      << "Size after filter was incorrect. Contents:\n" << MS;
-  for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
-    ASSERT_TRUE(I->gccSuffix() != "/one/two/three")
-        << "The filter should have removed " << *I;
-  }
-}
-
-TEST(MultilibTest, SetFilterObject) {
-  MultilibSet MS;
-  MS.Maybe(Multilib("orange"));
-  MS.Maybe(Multilib("pear"));
-  MS.Maybe(Multilib("plum"));
-  ASSERT_EQ((int)MS.size(), 1 /* Default */ +
-                            1 /* pear */ +
-                            1 /* plum */ +
-                            1 /* pear/plum */ +
-                            1 /* orange */ +
-                            1 /* orange/pear */ +
-                            1 /* orange/plum */ +
-                            1 /* orange/pear/plum */ )
-      << "Size before filter was incorrect. Contents:\n" << MS;
-  MS.FilterOut([](const Multilib &M) {
-    return StringRef(M.gccSuffix()).startswith("/p");
-  });
-  ASSERT_EQ((int)MS.size(), 1 /* Default */ +
-                            1 /* orange */ +
-                            1 /* orange/pear */ +
-                            1 /* orange/plum */ + 
-                            1 /* orange/pear/plum */ )
-      << "Size after filter was incorrect. Contents:\n" << MS;
-  for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
-    ASSERT_FALSE(StringRef(I->gccSuffix()).startswith("/p"))
-        << "The filter should have removed " << *I;
-  }
-}
-
-TEST(MultilibTest, SetSelection1) {
-  MultilibSet MS1 = MultilibSet()
-    .Maybe(Multilib("64").flag("+m64"));
-
-  Multilib::flags_list FlagM64;
-  FlagM64.push_back("+m64");
-  Multilib SelectionM64;
-  ASSERT_TRUE(MS1.select(FlagM64, SelectionM64))
-      << "Flag set was {\"+m64\"}, but selection not found";
-  ASSERT_TRUE(SelectionM64.gccSuffix() == "/64")
-      << "Selection picked " << SelectionM64 << " which was not expected";
-
-  Multilib::flags_list FlagNoM64;
-  FlagNoM64.push_back("-m64");
-  Multilib SelectionNoM64;
-  ASSERT_TRUE(MS1.select(FlagNoM64, SelectionNoM64))
-      << "Flag set was {\"-m64\"}, but selection not found";
-  ASSERT_TRUE(SelectionNoM64.gccSuffix() == "")
-      << "Selection picked " << SelectionNoM64 << " which was not expected";
-}
-
-TEST(MultilibTest, SetSelection2) {
-  MultilibSet MS2 = MultilibSet()
-    .Maybe(Multilib("el").flag("+EL"))
-    .Maybe(Multilib("sf").flag("+SF"));
-
-  for (unsigned I = 0; I < 4; ++I) {
-    bool IsEL = I & 0x1;
-    bool IsSF = I & 0x2;
-    Multilib::flags_list Flags;
-    if (IsEL)
-      Flags.push_back("+EL");
-    else
-      Flags.push_back("-EL");
-
-    if (IsSF)
-      Flags.push_back("+SF");
-    else
-      Flags.push_back("-SF");
-
-    Multilib Selection;
-    ASSERT_TRUE(MS2.select(Flags, Selection)) << "Selection failed for "
-                                              << (IsEL ? "+EL" : "-EL") << " "
-                                              << (IsSF ? "+SF" : "-SF");
-
-    std::string Suffix;
-    if (IsEL)
-      Suffix += "/el";
-    if (IsSF)
-      Suffix += "/sf";
-
-    ASSERT_EQ(Selection.gccSuffix(), Suffix) << "Selection picked " << Selection
-                                             << " which was not expected ";
-  }
-}
-
-TEST(MultilibTest, SetCombineWith) {
-  MultilibSet Coffee;
-  Coffee.push_back(Multilib("coffee"));
-  MultilibSet Milk;
-  Milk.push_back(Multilib("milk"));
-  MultilibSet Latte;
-  ASSERT_EQ(Latte.size(), (unsigned)0);
-  Latte.combineWith(Coffee);
-  ASSERT_EQ(Latte.size(), (unsigned)1);
-  Latte.combineWith(Milk);
-  ASSERT_EQ(Latte.size(), (unsigned)2);
 }
 
 TEST(MultilibTest, SetPriority) {
-  MultilibSet MS;
-  MS.push_back(Multilib("foo", {}, {}, 1).flag("+foo"));
-  MS.push_back(Multilib("bar", {}, {}, 2).flag("+bar"));
-
-  Multilib::flags_list Flags1;
-  Flags1.push_back("+foo");
-  Flags1.push_back("-bar");
+  MultilibSet MS({
+      Multilib("/foo", {}, {}, 1, {"+foo"}),
+      Multilib("/bar", {}, {}, 2, {"+bar"}),
+  });
+  Multilib::flags_list Flags1 = {"+foo", "-bar"};
   Multilib Selection1;
   ASSERT_TRUE(MS.select(Flags1, Selection1))
       << "Flag set was {\"+foo\"}, but selection not found";
   ASSERT_TRUE(Selection1.gccSuffix() == "/foo")
       << "Selection picked " << Selection1 << " which was not expected";
 
-  Multilib::flags_list Flags2;
-  Flags2.push_back("+foo");
-  Flags2.push_back("+bar");
+  Multilib::flags_list Flags2 = {"+foo", "+bar"};
   Multilib Selection2;
   ASSERT_TRUE(MS.select(Flags2, Selection2))
       << "Flag set was {\"+bar\"}, but selection not found";


        


More information about the cfe-commits mailing list