[TextAPI] Arch&Platform to Target

Summary:
This is a patch for updating TextAPI/Macho to read in targets as opposed to arch/platform.
This is because in previous versions tbd files only supported a single platform but that is no longer the case,
so, now its tracked by unique triples.
This precedes a seperate patch that will add  the TBD-v4 format

Reviewers: ributzka, steven_wu, plotfi, compnerd, smeenai

Reviewed By: ributzka

Subscribers: mgorny, hiraditya, dexonsmith, llvm-commits

Tags: #llvm

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

llvm-svn: 372396
diff --git a/llvm/lib/TextAPI/CMakeLists.txt b/llvm/lib/TextAPI/CMakeLists.txt
index 91b776b..d959fb9 100644
--- a/llvm/lib/TextAPI/CMakeLists.txt
+++ b/llvm/lib/TextAPI/CMakeLists.txt
@@ -5,7 +5,9 @@
   MachO/ArchitectureSet.cpp
   MachO/InterfaceFile.cpp
   MachO/PackedVersion.cpp
+  MachO/Platform.cpp
   MachO/Symbol.cpp
+  MachO/Target.cpp
   MachO/TextStub.cpp
   MachO/TextStubCommon.cpp
 
diff --git a/llvm/lib/TextAPI/MachO/Architecture.cpp b/llvm/lib/TextAPI/MachO/Architecture.cpp
index a66a982..699fb5f 100644
--- a/llvm/lib/TextAPI/MachO/Architecture.cpp
+++ b/llvm/lib/TextAPI/MachO/Architecture.cpp
@@ -68,6 +68,10 @@
   return std::make_pair(0, 0);
 }
 
+Architecture mapToArchitecture(const Triple &Target) {
+  return getArchitectureFromName(Target.getArchName());
+}
+
 raw_ostream &operator<<(raw_ostream &OS, Architecture Arch) {
   OS << getArchitectureName(Arch);
   return OS;
diff --git a/llvm/lib/TextAPI/MachO/InterfaceFile.cpp b/llvm/lib/TextAPI/MachO/InterfaceFile.cpp
index 54ba8cc..c40a952 100644
--- a/llvm/lib/TextAPI/MachO/InterfaceFile.cpp
+++ b/llvm/lib/TextAPI/MachO/InterfaceFile.cpp
@@ -27,36 +27,65 @@
 
   return Container.emplace(I, InstallName);
 }
+
+template <typename C>
+typename C::iterator addEntry(C &Container, const Target &Target_) {
+  auto Iter =
+      lower_bound(Container, Target_, [](const Target &LHS, const Target &RHS) {
+        return LHS < RHS;
+      });
+  if ((Iter != std::end(Container)) && !(Target_ < *Iter))
+    return Iter;
+
+  return Container.insert(Iter, Target_);
+}
 } // end namespace detail.
 
-void InterfaceFile::addAllowableClient(StringRef Name,
-                                       ArchitectureSet Architectures) {
-  auto Client = detail::addEntry(AllowableClients, Name);
-  Client->addArchitectures(Architectures);
+void InterfaceFileRef::addTarget(const Target &Target) {
+  detail::addEntry(Targets, Target);
+}
+
+void InterfaceFile::addAllowableClient(StringRef InstallName,
+                                       const Target &Target) {
+  auto Client = detail::addEntry(AllowableClients, InstallName);
+  Client->addTarget(Target);
 }
 
 void InterfaceFile::addReexportedLibrary(StringRef InstallName,
-                                         ArchitectureSet Architectures) {
+                                         const Target &Target) {
   auto Lib = detail::addEntry(ReexportedLibraries, InstallName);
-  Lib->addArchitectures(Architectures);
+  Lib->addTarget(Target);
 }
 
-void InterfaceFile::addUUID(Architecture Arch, StringRef UUID) {
-  auto I = partition_point(UUIDs,
-                           [=](const std::pair<Architecture, std::string> &O) {
-                             return O.first < Arch;
-                           });
+void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) {
+  auto Iter = lower_bound(ParentUmbrellas, Target_,
+                          [](const std::pair<Target, std::string> &LHS,
+                             Target RHS) { return LHS.first < RHS; });
 
-  if (I != UUIDs.end() && Arch == I->first) {
-    I->second = UUID;
+  if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) {
+    Iter->second = Parent;
     return;
   }
 
-  UUIDs.emplace(I, Arch, UUID);
+  ParentUmbrellas.emplace(Iter, Target_, Parent);
   return;
 }
 
-void InterfaceFile::addUUID(Architecture Arch, uint8_t UUID[16]) {
+void InterfaceFile::addUUID(const Target &Target_, StringRef UUID) {
+  auto Iter = lower_bound(UUIDs, Target_,
+                          [](const std::pair<Target, std::string> &LHS,
+                             Target RHS) { return LHS.first < RHS; });
+
+  if ((Iter != UUIDs.end()) && !(Target_ < Iter->first)) {
+    Iter->second = UUID;
+    return;
+  }
+
+  UUIDs.emplace(Iter, Target_, UUID);
+  return;
+}
+
+void InterfaceFile::addUUID(const Target &Target, uint8_t UUID[16]) {
   std::stringstream Stream;
   for (unsigned i = 0; i < 16; ++i) {
     if (i == 4 || i == 6 || i == 8 || i == 10)
@@ -64,17 +93,30 @@
     Stream << std::setfill('0') << std::setw(2) << std::uppercase << std::hex
            << static_cast<int>(UUID[i]);
   }
-  addUUID(Arch, Stream.str());
+  addUUID(Target, Stream.str());
+}
+
+void InterfaceFile::addTarget(const Target &Target) {
+  detail::addEntry(Targets, Target);
+}
+
+InterfaceFile::const_filtered_target_range
+InterfaceFile::targets(ArchitectureSet Archs) const {
+  std::function<bool(const Target &)> fn = [Archs](const Target &Target_) {
+    return Archs.has(Target_.Arch);
+  };
+  return make_filter_range(Targets, fn);
 }
 
 void InterfaceFile::addSymbol(SymbolKind Kind, StringRef Name,
-                              ArchitectureSet Archs, SymbolFlags Flags) {
+                              const TargetList &Targets, SymbolFlags Flags) {
   Name = copyString(Name);
   auto result = Symbols.try_emplace(SymbolsMapKey{Kind, Name}, nullptr);
   if (result.second)
-    result.first->second = new (Allocator) Symbol{Kind, Name, Archs, Flags};
+    result.first->second = new (Allocator) Symbol{Kind, Name, Targets, Flags};
   else
-    result.first->second->addArchitectures(Archs);
+    for (const auto &Target : Targets)
+      result.first->second->addTarget(Target);
 }
 
 } // end namespace MachO.
diff --git a/llvm/lib/TextAPI/MachO/Platform.cpp b/llvm/lib/TextAPI/MachO/Platform.cpp
new file mode 100644
index 0000000..ec62a9b
--- /dev/null
+++ b/llvm/lib/TextAPI/MachO/Platform.cpp
@@ -0,0 +1,61 @@
+//===- llvm/TextAPI/MachO/Platform.cpp - Platform ---------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementations of Platform Helper functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/TextAPI/MachO/Platform.h"
+
+namespace llvm {
+namespace MachO {
+
+PlatformKind mapToPlatformKind(const Triple &Target) {
+  switch (Target.getOS()) {
+  default:
+    return PlatformKind::unknown;
+  case Triple::MacOSX:
+    return PlatformKind::macOS;
+  case Triple::IOS:
+    return PlatformKind::iOS;
+  case Triple::TvOS:
+    return PlatformKind::tvOS;
+  case Triple::WatchOS:
+    return PlatformKind::watchOS;
+    // TODO: add bridgeOS once in llvm::Triple
+  }
+}
+
+PlatformSet mapToPlatformSet(ArrayRef<Triple> Targets) {
+  PlatformSet Result;
+  for (const auto &Target : Targets)
+    Result.insert(mapToPlatformKind(Target));
+  return Result;
+}
+
+StringRef getPlatformName(PlatformKind Platform) {
+  switch (Platform) {
+  case PlatformKind::unknown:
+    return "unknown";
+  case PlatformKind::macOS:
+    return "macOS";
+  case PlatformKind::iOS:
+    return "iOS";
+  case PlatformKind::tvOS:
+    return "tvOS";
+  case PlatformKind::watchOS:
+    return "watchOS";
+  case PlatformKind::bridgeOS:
+    return "bridgeOS";
+  }
+}
+
+} // end namespace MachO.
+} // end namespace llvm.
\ No newline at end of file
diff --git a/llvm/lib/TextAPI/MachO/Symbol.cpp b/llvm/lib/TextAPI/MachO/Symbol.cpp
index 731b264..9f2d817 100644
--- a/llvm/lib/TextAPI/MachO/Symbol.cpp
+++ b/llvm/lib/TextAPI/MachO/Symbol.cpp
@@ -45,5 +45,14 @@
 }
 #endif
 
+Symbol::const_filtered_target_range
+Symbol::targets(ArchitectureSet Architectures) const {
+  std::function<bool(const Target &)> FN =
+      [Architectures](const Target &Target) {
+        return Architectures.has(Target.Arch);
+      };
+  return make_filter_range(Targets, FN);
+}
+
 } // end namespace MachO.
 } // end namespace llvm.
diff --git a/llvm/lib/TextAPI/MachO/Target.cpp b/llvm/lib/TextAPI/MachO/Target.cpp
new file mode 100644
index 0000000..3052aa5
--- /dev/null
+++ b/llvm/lib/TextAPI/MachO/Target.cpp
@@ -0,0 +1,45 @@
+//===- tapi/Core/Target.cpp - Target ----------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TextAPI/MachO/Target.h"
+
+namespace llvm {
+namespace MachO {
+
+Target::operator std::string() const {
+  return (getArchitectureName(Arch) + " (" + getPlatformName(Platform) + ")")
+      .str();
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const Target &Target) {
+  OS << std::string(Target);
+  return OS;
+}
+
+PlatformSet mapToPlatformSet(ArrayRef<Target> Targets) {
+  PlatformSet Result;
+  for (const auto &Target : Targets)
+    Result.insert(Target.Platform);
+  return Result;
+}
+
+ArchitectureSet mapToArchitectureSet(ArrayRef<Target> Targets) {
+  ArchitectureSet Result;
+  for (const auto &Target : Targets)
+    Result.set(Target.Arch);
+  return Result;
+}
+
+} // end namespace MachO.
+} // end namespace llvm.
\ No newline at end of file
diff --git a/llvm/lib/TextAPI/MachO/TextStub.cpp b/llvm/lib/TextAPI/MachO/TextStub.cpp
index 37186673..1f1d39e 100644
--- a/llvm/lib/TextAPI/MachO/TextStub.cpp
+++ b/llvm/lib/TextAPI/MachO/TextStub.cpp
@@ -246,7 +246,7 @@
     NormalizedTBD(IO &IO, const InterfaceFile *&File) {
       Architectures = File->getArchitectures();
       UUIDs = File->uuids();
-      Platform = File->getPlatform();
+      Platforms = File->getPlatforms();
       InstallName = File->getInstallName();
       CurrentVersion = PackedVersion(File->getCurrentVersion());
       CompatibilityVersion = PackedVersion(File->getCompatibilityVersion());
@@ -263,7 +263,10 @@
       if (File->isInstallAPI())
         Flags |= TBDFlags::InstallAPI;
 
-      ParentUmbrella = File->getParentUmbrella();
+      for (const auto &Iter : File->umbrellas()) {
+        ParentUmbrella = Iter.second;
+        break;
+      }
 
       std::set<ArchitectureSet> ArchSet;
       for (const auto &Library : File->allowableClients())
@@ -396,6 +399,17 @@
       }
     }
 
+    TargetList synthesizeTargets(ArchitectureSet Architectures,
+                                 const PlatformSet &Platforms) {
+      TargetList Targets;
+
+      for (auto Platform : Platforms) {
+        for (const auto &&Architecture : Architectures)
+          Targets.emplace_back(Architecture, Platform);
+      }
+      return Targets;
+    }
+
     const InterfaceFile *denormalize(IO &IO) {
       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
       assert(Ctx);
@@ -403,16 +417,16 @@
       auto *File = new InterfaceFile;
       File->setPath(Ctx->Path);
       File->setFileType(Ctx->FileKind);
+      File->addTargets(synthesizeTargets(Architectures, Platforms));
       for (auto &ID : UUIDs)
         File->addUUID(ID.first, ID.second);
-      File->setPlatform(Platform);
-      File->setArchitectures(Architectures);
       File->setInstallName(InstallName);
       File->setCurrentVersion(CurrentVersion);
       File->setCompatibilityVersion(CompatibilityVersion);
       File->setSwiftABIVersion(SwiftABIVersion);
       File->setObjCConstraint(ObjCConstraint);
-      File->setParentUmbrella(ParentUmbrella);
+      for (const auto &Target : File->targets())
+        File->addParentUmbrella(Target, ParentUmbrella);
 
       if (Ctx->FileKind == FileType::TBD_V1) {
         File->setTwoLevelNamespace();
@@ -425,76 +439,80 @@
       }
 
       for (const auto &Section : Exports) {
-        for (const auto &Library : Section.AllowableClients)
-          File->addAllowableClient(Library, Section.Architectures);
-        for (const auto &Library : Section.ReexportedLibraries)
-          File->addReexportedLibrary(Library, Section.Architectures);
+        const auto Targets =
+            synthesizeTargets(Section.Architectures, Platforms);
+
+        for (const auto &Lib : Section.AllowableClients)
+          for (const auto &Target : Targets)
+            File->addAllowableClient(Lib, Target);
+
+        for (const auto &Lib : Section.ReexportedLibraries)
+          for (const auto &Target : Targets)
+            File->addReexportedLibrary(Lib, Target);
 
         for (const auto &Symbol : Section.Symbols) {
           if (Ctx->FileKind != FileType::TBD_V3 &&
               Symbol.value.startswith("_OBJC_EHTYPE_$_"))
             File->addSymbol(SymbolKind::ObjectiveCClassEHType,
-                            Symbol.value.drop_front(15), Section.Architectures);
+                            Symbol.value.drop_front(15), Targets);
           else
-            File->addSymbol(SymbolKind::GlobalSymbol, Symbol,
-                            Section.Architectures);
+            File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets);
         }
         for (auto &Symbol : Section.Classes) {
           auto Name = Symbol.value;
           if (Ctx->FileKind != FileType::TBD_V3)
             Name = Name.drop_front();
-          File->addSymbol(SymbolKind::ObjectiveCClass, Name,
-                          Section.Architectures);
+          File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets);
         }
         for (auto &Symbol : Section.ClassEHs)
-          File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol,
-                          Section.Architectures);
+          File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets);
         for (auto &Symbol : Section.IVars) {
           auto Name = Symbol.value;
           if (Ctx->FileKind != FileType::TBD_V3)
             Name = Name.drop_front();
           File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name,
-                          Section.Architectures);
+                          Targets);
         }
         for (auto &Symbol : Section.WeakDefSymbols)
-          File->addSymbol(SymbolKind::GlobalSymbol, Symbol,
-                          Section.Architectures, SymbolFlags::WeakDefined);
+          File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
+                          SymbolFlags::WeakDefined);
         for (auto &Symbol : Section.TLVSymbols)
-          File->addSymbol(SymbolKind::GlobalSymbol, Symbol,
-                          Section.Architectures, SymbolFlags::ThreadLocalValue);
+          File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
+                          SymbolFlags::ThreadLocalValue);
       }
 
       for (const auto &Section : Undefineds) {
+        const auto Targets =
+            synthesizeTargets(Section.Architectures, Platforms);
         for (auto &Symbol : Section.Symbols) {
           if (Ctx->FileKind != FileType::TBD_V3 &&
               Symbol.value.startswith("_OBJC_EHTYPE_$_"))
             File->addSymbol(SymbolKind::ObjectiveCClassEHType,
-                            Symbol.value.drop_front(15), Section.Architectures,
+                            Symbol.value.drop_front(15), Targets,
                             SymbolFlags::Undefined);
           else
-            File->addSymbol(SymbolKind::GlobalSymbol, Symbol,
-                            Section.Architectures, SymbolFlags::Undefined);
+            File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
+                            SymbolFlags::Undefined);
         }
         for (auto &Symbol : Section.Classes) {
           auto Name = Symbol.value;
           if (Ctx->FileKind != FileType::TBD_V3)
             Name = Name.drop_front();
-          File->addSymbol(SymbolKind::ObjectiveCClass, Name,
-                          Section.Architectures, SymbolFlags::Undefined);
+          File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets,
+                          SymbolFlags::Undefined);
         }
         for (auto &Symbol : Section.ClassEHs)
-          File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol,
-                          Section.Architectures, SymbolFlags::Undefined);
+          File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets,
+                          SymbolFlags::Undefined);
         for (auto &Symbol : Section.IVars) {
           auto Name = Symbol.value;
           if (Ctx->FileKind != FileType::TBD_V3)
             Name = Name.drop_front();
-          File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name,
-                          Section.Architectures, SymbolFlags::Undefined);
+          File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets,
+                          SymbolFlags::Undefined);
         }
         for (auto &Symbol : Section.WeakRefSymbols)
-          File->addSymbol(SymbolKind::GlobalSymbol, Symbol,
-                          Section.Architectures,
+          File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
                           SymbolFlags::Undefined | SymbolFlags::WeakReferenced);
       }
 
@@ -513,7 +531,7 @@
 
     std::vector<Architecture> Architectures;
     std::vector<UUID> UUIDs;
-    PlatformKind Platform{PlatformKind::unknown};
+    PlatformSet Platforms;
     StringRef InstallName;
     PackedVersion CurrentVersion;
     PackedVersion CompatibilityVersion;
@@ -567,7 +585,7 @@
     IO.mapRequired("archs", Keys->Architectures);
     if (Ctx->FileKind != FileType::TBD_V1)
       IO.mapOptional("uuids", Keys->UUIDs);
-    IO.mapRequired("platform", Keys->Platform);
+    IO.mapRequired("platform", Keys->Platforms);
     if (Ctx->FileKind != FileType::TBD_V1)
       IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
     IO.mapRequired("install-name", Keys->InstallName);
diff --git a/llvm/lib/TextAPI/MachO/TextStubCommon.cpp b/llvm/lib/TextAPI/MachO/TextStubCommon.cpp
index 00382cd..313b040 100644
--- a/llvm/lib/TextAPI/MachO/TextStubCommon.cpp
+++ b/llvm/lib/TextAPI/MachO/TextStubCommon.cpp
@@ -41,9 +41,10 @@
   IO.enumCase(Constraint, "gc", ObjCConstraintType::GC);
 }
 
-void ScalarTraits<PlatformKind>::output(const PlatformKind &Value, void *,
-                                        raw_ostream &OS) {
-  switch (Value) {
+void ScalarTraits<PlatformSet>::output(const PlatformSet &Values, void *IO,
+                                       raw_ostream &OS) {
+  assert(Values.size() == 1U);
+  switch (*Values.begin()) {
   default:
     llvm_unreachable("unexpected platform");
     break;
@@ -64,21 +65,26 @@
     break;
   }
 }
-StringRef ScalarTraits<PlatformKind>::input(StringRef Scalar, void *,
-                                            PlatformKind &Value) {
-  Value = StringSwitch<PlatformKind>(Scalar)
-              .Case("macosx", PlatformKind::macOS)
-              .Case("ios", PlatformKind::iOS)
-              .Case("watchos", PlatformKind::watchOS)
-              .Case("tvos", PlatformKind::tvOS)
-              .Case("bridgeos", PlatformKind::bridgeOS)
-              .Default(PlatformKind::unknown);
 
-  if (Value == PlatformKind::unknown)
+StringRef ScalarTraits<PlatformSet>::input(StringRef Scalar, void *IO,
+                                           PlatformSet &Values) {
+  auto Platform = StringSwitch<PlatformKind>(Scalar)
+                      .Case("unknown", PlatformKind::unknown)
+                      .Case("macosx", PlatformKind::macOS)
+                      .Case("ios", PlatformKind::iOS)
+                      .Case("watchos", PlatformKind::watchOS)
+                      .Case("tvos", PlatformKind::tvOS)
+                      .Case("bridgeos", PlatformKind::bridgeOS)
+                      .Default(PlatformKind::unknown);
+
+  if (Platform == PlatformKind::unknown)
     return "unknown platform";
+
+  Values.insert(Platform);
   return {};
 }
-QuotingType ScalarTraits<PlatformKind>::mustQuote(StringRef) {
+
+QuotingType ScalarTraits<PlatformSet>::mustQuote(StringRef) {
   return QuotingType::None;
 }
 
@@ -166,10 +172,11 @@
   auto UUID = Split.second.trim();
   if (UUID.empty())
     return "invalid uuid string pair";
-  Value.first = getArchitectureFromName(Arch);
   Value.second = UUID;
+  Value.first = Target{getArchitectureFromName(Arch), PlatformKind::unknown};
   return {};
 }
+
 QuotingType ScalarTraits<UUID>::mustQuote(StringRef) {
   return QuotingType::Single;
 }
diff --git a/llvm/lib/TextAPI/MachO/TextStubCommon.h b/llvm/lib/TextAPI/MachO/TextStubCommon.h
index c4dd107..a558cbc 100644
--- a/llvm/lib/TextAPI/MachO/TextStubCommon.h
+++ b/llvm/lib/TextAPI/MachO/TextStubCommon.h
@@ -21,7 +21,7 @@
 #include "llvm/TextAPI/MachO/InterfaceFile.h"
 #include "llvm/TextAPI/MachO/PackedVersion.h"
 
-using UUID = std::pair<llvm::MachO::Architecture, std::string>;
+using UUID = std::pair<llvm::MachO::Target, std::string>;
 
 LLVM_YAML_STRONG_TYPEDEF(llvm::StringRef, FlowStringRef)
 LLVM_YAML_STRONG_TYPEDEF(uint8_t, SwiftVersion)
@@ -41,9 +41,9 @@
   static void enumeration(IO &, MachO::ObjCConstraintType &);
 };
 
-template <> struct ScalarTraits<MachO::PlatformKind> {
-  static void output(const MachO::PlatformKind &, void *, raw_ostream &);
-  static StringRef input(StringRef, void *, MachO::PlatformKind &);
+template <> struct ScalarTraits<MachO::PlatformSet> {
+  static void output(const MachO::PlatformSet &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, MachO::PlatformSet &);
   static QuotingType mustQuote(StringRef);
 };