llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Cyndy Ishida (cyndyishida)

<details>
<summary>Changes</summary>

With the introduction of tbd-v5 holding rpaths, the order in which attributes 
are passed to `clang-installapi` must be represented in tbd files. Previously, 
all of these attributes were stored in a non-deterministic `StringMap`. 
Instead, hold them in a custom collection with an underlying vector to continue 
supporting searching by attribute.

Resolves errors when building with reverse-iteration.

---
Full diff: https://github.com/llvm/llvm-project/pull/139087.diff


6 Files Affected:

- (modified) clang/include/clang/InstallAPI/DylibVerifier.h (+23-1) 
- (modified) clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp (+5-5) 
- (modified) clang/lib/InstallAPI/DiagnosticBuilderWrappers.h (+2-1) 
- (modified) clang/lib/InstallAPI/DylibVerifier.cpp (+35-14) 
- (modified) clang/tools/clang-installapi/ClangInstallAPI.cpp (+3-3) 
- (modified) clang/tools/clang-installapi/Options.cpp (+19-22) 


``````````diff
diff --git a/clang/include/clang/InstallAPI/DylibVerifier.h 
b/clang/include/clang/InstallAPI/DylibVerifier.h
index 333f0cff077fd..4cf70a8adc9bc 100644
--- a/clang/include/clang/InstallAPI/DylibVerifier.h
+++ b/clang/include/clang/InstallAPI/DylibVerifier.h
@@ -25,9 +25,31 @@ enum class VerificationMode {
   Pedantic,
 };
 
-using LibAttrs = llvm::StringMap<ArchitectureSet>;
 using ReexportedInterfaces = llvm::SmallVector<llvm::MachO::InterfaceFile, 8>;
 
+/// Represents dynamic library specific attributes that are tied to
+/// architecture slices. It is commonly used for comparing options
+/// passed on the command line to installapi and what exists in dylib load
+/// commands.
+class LibAttrs {
+public:
+  using Entry = std::pair<std::string, ArchitectureSet>;
+  using AttrsToArchs = llvm::SmallVector<Entry, 10>;
+
+  // Mutable access to architecture set tied to the input attribute.
+  ArchitectureSet &getArchSet(StringRef Attr);
+  // Get entry based on the attribute.
+  std::optional<Entry> find(StringRef Attr) const;
+  // Immutable access to underlying container.
+  const AttrsToArchs &get() const { return LibraryAttributes; };
+  // Mutable access to underlying container.
+  AttrsToArchs &get() { return LibraryAttributes; };
+  bool operator==(const LibAttrs &Other) const { return Other.get() == get(); 
};
+
+private:
+  AttrsToArchs LibraryAttributes;
+};
+
 // Pointers to information about a zippered declaration used for
 // querying and reporting violations against different
 // declarations that all map to the same symbol.
diff --git a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp 
b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp
index c8d07f229902b..fd9db8113a41e 100644
--- a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp
+++ b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp
@@ -97,12 +97,12 @@ const DiagnosticBuilder &operator<<(const DiagnosticBuilder 
&DB,
 
 const clang::DiagnosticBuilder &
 operator<<(const clang::DiagnosticBuilder &DB,
-           const StringMapEntry<ArchitectureSet> &LibAttr) {
-  std::string IFAsString;
-  raw_string_ostream OS(IFAsString);
+           const clang::installapi::LibAttrs::Entry &LibAttr) {
+  std::string Entry;
+  raw_string_ostream OS(Entry);
 
-  OS << LibAttr.getKey() << " [ " << LibAttr.getValue() << " ]";
-  DB.AddString(IFAsString);
+  OS << LibAttr.first << " [ " << LibAttr.second << " ]";
+  DB.AddString(Entry);
   return DB;
 }
 
diff --git a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.h 
b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.h
index 48cfefbf65e6b..ba24ee415dfcf 100644
--- a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.h
+++ b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H
 
 #include "clang/Basic/Diagnostic.h"
+#include "clang/InstallAPI/DylibVerifier.h"
 #include "llvm/TextAPI/Architecture.h"
 #include "llvm/TextAPI/ArchitectureSet.h"
 #include "llvm/TextAPI/InterfaceFile.h"
@@ -42,7 +43,7 @@ const clang::DiagnosticBuilder &operator<<(const 
clang::DiagnosticBuilder &DB,
 
 const clang::DiagnosticBuilder &
 operator<<(const clang::DiagnosticBuilder &DB,
-           const StringMapEntry<ArchitectureSet> &LibAttr);
+           const clang::installapi::LibAttrs::Entry &LibAttr);
 
 } // namespace MachO
 } // namespace llvm
diff --git a/clang/lib/InstallAPI/DylibVerifier.cpp 
b/clang/lib/InstallAPI/DylibVerifier.cpp
index d5d760767b41f..45c84c00d9236 100644
--- a/clang/lib/InstallAPI/DylibVerifier.cpp
+++ b/clang/lib/InstallAPI/DylibVerifier.cpp
@@ -18,6 +18,25 @@ using namespace llvm::MachO;
 namespace clang {
 namespace installapi {
 
+ArchitectureSet &LibAttrs::getArchSet(StringRef Attr) {
+  auto *It = llvm::find_if(LibraryAttributes, [&Attr](const auto &Input) {
+    return Attr == Input.first;
+  });
+  if (It != LibraryAttributes.end())
+    return It->second;
+  LibraryAttributes.push_back({Attr.str(), ArchitectureSet()});
+  return LibraryAttributes.back().second;
+}
+
+std::optional<LibAttrs::Entry> LibAttrs::find(StringRef Attr) const {
+  auto *It = llvm::find_if(LibraryAttributes, [&Attr](const auto &Input) {
+    return Attr == Input.first;
+  });
+  if (It == LibraryAttributes.end())
+    return std::nullopt;
+  return *It;
+}
+
 /// Metadata stored about a mapping of a declaration to a symbol.
 struct DylibVerifier::SymbolContext {
   // Name to use for all querying and verification
@@ -825,13 +844,13 @@ bool DylibVerifier::verifyBinaryAttrs(const 
ArrayRef<Target> ProvidedTargets,
     DylibTargets.push_back(RS->getTarget());
     const BinaryAttrs &BinInfo = RS->getBinaryAttrs();
     for (const StringRef LibName : BinInfo.RexportedLibraries)
-      DylibReexports[LibName].set(DylibTargets.back().Arch);
+      DylibReexports.getArchSet(LibName).set(DylibTargets.back().Arch);
     for (const StringRef LibName : BinInfo.AllowableClients)
-      DylibClients[LibName].set(DylibTargets.back().Arch);
+      DylibClients.getArchSet(LibName).set(DylibTargets.back().Arch);
     // Compare attributes that are only representable in >= TBD_V5.
     if (FT >= FileType::TBD_V5)
       for (const StringRef Name : BinInfo.RPaths)
-        DylibRPaths[Name].set(DylibTargets.back().Arch);
+        DylibRPaths.getArchSet(Name).set(DylibTargets.back().Arch);
   }
 
   // Check targets first.
@@ -923,31 +942,33 @@ bool DylibVerifier::verifyBinaryAttrs(const 
ArrayRef<Target> ProvidedTargets,
     if (Provided == Dylib)
       return true;
 
-    for (const llvm::StringMapEntry<ArchitectureSet> &PAttr : Provided) {
-      const auto DAttrIt = Dylib.find(PAttr.getKey());
-      if (DAttrIt == Dylib.end()) {
-        Ctx.Diag->Report(DiagID_missing) << "binary file" << PAttr;
+    for (const LibAttrs::Entry &PEntry : Provided.get()) {
+      const auto &[PAttr, PArchSet] = PEntry;
+      auto DAttrEntry = Dylib.find(PAttr);
+      if (!DAttrEntry) {
+        Ctx.Diag->Report(DiagID_missing) << "binary file" << PEntry;
         if (Fatal)
           return false;
       }
 
-      if (PAttr.getValue() != DAttrIt->getValue()) {
-        Ctx.Diag->Report(DiagID_mismatch) << PAttr << *DAttrIt;
+      if (PArchSet != DAttrEntry->second) {
+        Ctx.Diag->Report(DiagID_mismatch) << PEntry << *DAttrEntry;
         if (Fatal)
           return false;
       }
     }
 
-    for (const llvm::StringMapEntry<ArchitectureSet> &DAttr : Dylib) {
-      const auto PAttrIt = Provided.find(DAttr.getKey());
-      if (PAttrIt == Provided.end()) {
-        Ctx.Diag->Report(DiagID_missing) << "installAPI option" << DAttr;
+    for (const LibAttrs::Entry &DEntry : Dylib.get()) {
+      const auto &[DAttr, DArchSet] = DEntry;
+      const auto &PAttrEntry = Provided.find(DAttr);
+      if (!PAttrEntry) {
+        Ctx.Diag->Report(DiagID_missing) << "installAPI option" << DEntry;
         if (!Fatal)
           continue;
         return false;
       }
 
-      if (PAttrIt->getValue() != DAttr.getValue()) {
+      if (PAttrEntry->second != DArchSet) {
         if (Fatal)
           llvm_unreachable("this case was already covered above.");
       }
diff --git a/clang/tools/clang-installapi/ClangInstallAPI.cpp 
b/clang/tools/clang-installapi/ClangInstallAPI.cpp
index 37b69ccf4e00e..14e7b53d74b09 100644
--- a/clang/tools/clang-installapi/ClangInstallAPI.cpp
+++ b/clang/tools/clang-installapi/ClangInstallAPI.cpp
@@ -170,9 +170,9 @@ static bool run(ArrayRef<const char *> Args, const char 
*ProgName) {
       [&IF](
           const auto &Attrs,
           std::function<void(InterfaceFile *, StringRef, const Target &)> Add) 
{
-        for (const auto &Lib : Attrs)
-          for (const auto &T : IF.targets(Lib.getValue()))
-            Add(&IF, Lib.getKey(), T);
+        for (const auto &[Attr, ArchSet] : Attrs.get())
+          for (const auto &T : IF.targets(ArchSet))
+            Add(&IF, Attr, T);
       };
 
   assignLibAttrs(Opts.LinkerOpts.AllowableClients,
diff --git a/clang/tools/clang-installapi/Options.cpp 
b/clang/tools/clang-installapi/Options.cpp
index 9bc168c8cd4f8..73f5470b82486 100644
--- a/clang/tools/clang-installapi/Options.cpp
+++ b/clang/tools/clang-installapi/Options.cpp
@@ -610,35 +610,35 @@ 
Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
 
   for (const Arg *A : ParsedArgs.filtered(OPT_allowable_client)) {
     auto It = ArgToArchMap.find(A);
-    LinkerOpts.AllowableClients[A->getValue()] =
+    LinkerOpts.AllowableClients.getArchSet(A->getValue()) =
         It != ArgToArchMap.end() ? It->second : ArchitectureSet();
     A->claim();
   }
 
   for (const Arg *A : ParsedArgs.filtered(OPT_reexport_l)) {
     auto It = ArgToArchMap.find(A);
-    LinkerOpts.ReexportedLibraries[A->getValue()] =
+    LinkerOpts.ReexportedLibraries.getArchSet(A->getValue()) =
         It != ArgToArchMap.end() ? It->second : ArchitectureSet();
     A->claim();
   }
 
   for (const Arg *A : ParsedArgs.filtered(OPT_reexport_library)) {
     auto It = ArgToArchMap.find(A);
-    LinkerOpts.ReexportedLibraryPaths[A->getValue()] =
+    LinkerOpts.ReexportedLibraryPaths.getArchSet(A->getValue()) =
         It != ArgToArchMap.end() ? It->second : ArchitectureSet();
     A->claim();
   }
 
   for (const Arg *A : ParsedArgs.filtered(OPT_reexport_framework)) {
     auto It = ArgToArchMap.find(A);
-    LinkerOpts.ReexportedFrameworks[A->getValue()] =
+    LinkerOpts.ReexportedFrameworks.getArchSet(A->getValue()) =
         It != ArgToArchMap.end() ? It->second : ArchitectureSet();
     A->claim();
   }
 
   for (const Arg *A : ParsedArgs.filtered(OPT_rpath)) {
     auto It = ArgToArchMap.find(A);
-    LinkerOpts.RPaths[A->getValue()] =
+    LinkerOpts.RPaths.getArchSet(A->getValue()) =
         It != ArgToArchMap.end() ? It->second : ArchitectureSet();
     A->claim();
   }
@@ -733,9 +733,9 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
   llvm::for_each(DriverOpts.Targets,
                  [&AllArchs](const auto &T) { AllArchs.set(T.first.Arch); });
   auto assignDefaultLibAttrs = [&AllArchs](LibAttrs &Attrs) {
-    for (StringMapEntry<ArchitectureSet> &Entry : Attrs)
-      if (Entry.getValue().empty())
-        Entry.setValue(AllArchs);
+    for (auto &[_, Archs] : Attrs.get())
+      if (Archs.empty())
+        Archs = AllArchs;
   };
   assignDefaultLibAttrs(LinkerOpts.AllowableClients);
   assignDefaultLibAttrs(LinkerOpts.ReexportedFrameworks);
@@ -789,7 +789,7 @@ std::pair<LibAttrs, ReexportedInterfaces> 
Options::getReexportedLibraries() {
     std::unique_ptr<InterfaceFile> Reexport = std::move(*ReexportIFOrErr);
     StringRef InstallName = Reexport->getInstallName();
     assert(!InstallName.empty() && "Parse error for install name");
-    Reexports.insert({InstallName, Archs});
+    Reexports.getArchSet(InstallName) = Archs;
     ReexportIFs.emplace_back(std::move(*Reexport));
     return true;
   };
@@ -802,39 +802,36 @@ std::pair<LibAttrs, ReexportedInterfaces> 
Options::getReexportedLibraries() {
   for (const PlatformType P : Platforms) {
     PathSeq PlatformSearchPaths = getPathsForPlatform(FEOpts.SystemFwkPaths, 
P);
     llvm::append_range(FwkSearchPaths, PlatformSearchPaths);
-    for (const StringMapEntry<ArchitectureSet> &Lib :
-         LinkerOpts.ReexportedFrameworks) {
-      std::string Name = (Lib.getKey() + ".framework/" + Lib.getKey()).str();
+    for (const auto &[Lib, Archs] : LinkerOpts.ReexportedFrameworks.get()) {
+      std::string Name = (Lib + ".framework/" + Lib);
       std::string Path = findLibrary(Name, *FM, FwkSearchPaths, {}, {});
       if (Path.empty()) {
-        Diags->Report(diag::err_cannot_find_reexport) << false << Lib.getKey();
+        Diags->Report(diag::err_cannot_find_reexport) << false << Lib;
         return {};
       }
       if (DriverOpts.TraceLibraryLocation)
         errs() << Path << "\n";
 
-      AccumulateReexports(Path, Lib.getValue());
+      AccumulateReexports(Path, Archs);
     }
     FwkSearchPaths.resize(FwkSearchPaths.size() - PlatformSearchPaths.size());
   }
 
-  for (const StringMapEntry<ArchitectureSet> &Lib :
-       LinkerOpts.ReexportedLibraries) {
-    std::string Name = "lib" + Lib.getKey().str() + ".dylib";
+  for (const auto &[Lib, Archs] : LinkerOpts.ReexportedLibraries.get()) {
+    std::string Name = "lib" + Lib + ".dylib";
     std::string Path = findLibrary(Name, *FM, {}, LinkerOpts.LibPaths, {});
     if (Path.empty()) {
-      Diags->Report(diag::err_cannot_find_reexport) << true << Lib.getKey();
+      Diags->Report(diag::err_cannot_find_reexport) << true << Lib;
       return {};
     }
     if (DriverOpts.TraceLibraryLocation)
       errs() << Path << "\n";
 
-    AccumulateReexports(Path, Lib.getValue());
+    AccumulateReexports(Path, Archs);
   }
 
-  for (const StringMapEntry<ArchitectureSet> &Lib :
-       LinkerOpts.ReexportedLibraryPaths)
-    AccumulateReexports(Lib.getKey(), Lib.getValue());
+  for (const auto &[Lib, Archs] : LinkerOpts.ReexportedLibraryPaths.get())
+    AccumulateReexports(Lib, Archs);
 
   return {std::move(Reexports), std::move(ReexportIFs)};
 }

``````````

</details>


https://github.com/llvm/llvm-project/pull/139087
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to