[lld] [llvm] [GlobPattern] add AsLiteral to help lld determine if a symbol is literal (PR #215854)

Peter Rong via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 24 16:50:00 PDT 2026


https://github.com/DataCorrupted updated https://github.com/llvm/llvm-project/pull/215854

>From 2bfa769bcfb889cf87910fa09dd833e1f224e7c9 Mon Sep 17 00:00:00 2001
From: Peter Rong <PeterRong at meta.com>
Date: Wed, 12 Aug 2026 10:39:50 -0700
Subject: [PATCH 1/4] [GlobPattern] add AsLiteral to help lld determine if a
 symbol is literal

---
 lld/MachO/Driver.cpp                          | 19 ++++--
 .../MachO/exported-symbols-list-escapes.s     | 65 +++++++++++++++++++
 llvm/include/llvm/Support/GlobPattern.h       | 15 +++++
 llvm/lib/Support/GlobPattern.cpp              | 30 +++++++++
 llvm/unittests/Support/GlobPatternTest.cpp    | 57 ++++++++++++++++
 5 files changed, 181 insertions(+), 5 deletions(-)
 create mode 100644 lld/test/MachO/exported-symbols-list-escapes.s

diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 2864c6d28fa49..2fa959eaf7e93 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1360,12 +1360,21 @@ void SymbolPatterns::clear() {
 }
 
 void SymbolPatterns::insert(StringRef symbolName) {
-  if (symbolName.find_first_of("*?[]") == StringRef::npos)
-    literals.insert(CachedHashStringRef(symbolName));
-  else if (Expected<GlobPattern> pattern = GlobPattern::create(symbolName))
-    globs.emplace_back(*pattern);
-  else
+  Expected<GlobPattern> pattern = GlobPattern::create(symbolName);
+  if (!pattern) {
+    llvm::consumeError(pattern.takeError());
     error("invalid symbol-name pattern: " + symbolName);
+    return;
+  }
+  // A pattern that denotes a single string is kept as a literal: literals are
+  // matched by hash lookup, and only literals seed the force-load of lazy
+  // archive members below.
+  SmallVector<char, 128> storage;
+  if (std::optional<StringRef> literal = pattern->asLiteral(storage)) {
+    literals.insert(CachedHashStringRef(saver().save(*literal)));
+    return;
+  }
+  globs.emplace_back(std::move(*pattern));
 }
 
 bool SymbolPatterns::matchLiteral(StringRef symbolName) const {
diff --git a/lld/test/MachO/exported-symbols-list-escapes.s b/lld/test/MachO/exported-symbols-list-escapes.s
new file mode 100644
index 0000000000000..169ce49435174
--- /dev/null
+++ b/lld/test/MachO/exported-symbols-list-escapes.s
@@ -0,0 +1,65 @@
+# REQUIRES: x86
+
+## An -exported_symbols_list entry may escape glob metacharacters with a
+## backslash to name a symbol literally. This matters for Objective-C direct
+## methods, whose names contain square brackets that would otherwise be parsed
+## as a character class and match nothing.
+
+# RUN: rm -rf %t; split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/bracket.s -o %t/bracket.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/anchor.s -o %t/anchor.o
+# RUN: llvm-ar --format=darwin rcs %t/bracket.a %t/bracket.o
+
+## An escaped entry is a literal: it exact-matches, and because literals seed
+## addUndefined it also force-loads the archive member that defines it.
+# RUN: %lld -dylib -exported_symbols_list %t/escaped.txt \
+# RUN:     %t/anchor.o %t/bracket.a -o %t/escaped.dylib
+# RUN: llvm-nm --extern-only %t/escaped.dylib | FileCheck --check-prefix=ESCAPED %s
+
+# ESCAPED: -[C m]D
+
+## An unescaped entry keeps its glob meaning: "[C m]" is a character class, so
+## it does not match the real symbol and nothing is force-loaded.
+# RUN: %lld -dylib -exported_symbols_list %t/unescaped.txt \
+# RUN:     %t/anchor.o %t/bracket.a -o %t/unescaped.dylib
+# RUN: llvm-nm --extern-only %t/unescaped.dylib | \
+# RUN:     FileCheck --check-prefix=UNESCAPED --allow-empty %s
+
+# UNESCAPED-NOT: -[C m]D
+
+## Escaping a star names a symbol that literally contains one, rather than
+## matching any symbol by prefix.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/star.s -o %t/star.o
+# RUN: %lld -dylib -exported_symbols_list %t/escaped-star.txt \
+# RUN:     %t/star.o -o %t/star.dylib
+# RUN: llvm-nm --extern-only %t/star.dylib | FileCheck --check-prefix=STAR %s
+
+# STAR-DAG: _lit*eral
+# STAR-NOT: _litoteral
+
+#--- bracket.s
+.globl "_-[C m]D"
+"_-[C m]D":
+  retq
+
+#--- anchor.s
+.globl _anchor
+_anchor:
+  retq
+
+#--- star.s
+.globl "_lit*eral"
+"_lit*eral":
+  retq
+.globl _litoteral
+_litoteral:
+  retq
+
+#--- escaped.txt
+_-\[C m\]D
+
+#--- unescaped.txt
+_-[C m]D
+
+#--- escaped-star.txt
+_lit\*eral
diff --git a/llvm/include/llvm/Support/GlobPattern.h b/llvm/include/llvm/Support/GlobPattern.h
index 8c84c93834c6b..7b4875cd093db 100644
--- a/llvm/include/llvm/Support/GlobPattern.h
+++ b/llvm/include/llvm/Support/GlobPattern.h
@@ -61,6 +61,17 @@ class GlobPattern {
   /// \returns \p true if \p S matches this glob pattern
   LLVM_ABI bool match(StringRef S) const;
 
+  /// \returns the single string this pattern matches, if the pattern contains
+  /// no unescaped metacharacters; otherwise std::nullopt. Escapes are resolved,
+  /// so `a\*b` yields `a*b`. Characters that are only special in context (`]`,
+  /// `}`, `,`) do not make a pattern non-literal.
+  ///
+  /// \p Storage is used only when escapes have to be resolved; otherwise the
+  /// result aliases the text passed to create(). The result is valid for as
+  /// long as both remain alive.
+  LLVM_ABI std::optional<StringRef>
+  asLiteral(SmallVectorImpl<char> &Storage) const;
+
   // Returns true for glob pattern "*". Can be used to avoid expensive
   // preparation/acquisition of the input for match().
   bool isTrivialMatchAll() const {
@@ -97,6 +108,8 @@ class GlobPattern {
     /// \returns \p true if \p S matches this glob pattern
     LLVM_ABI bool match(StringRef S, bool SlashAgnostic) const;
     StringRef getPat() const { return StringRef(Pat.data(), Pat.size()); }
+    /// \returns \p true if this sub-pattern matches exactly one string.
+    bool isLiteral() const { return Brackets.empty() && !HasWildcard; }
 
     // Brackets with their end position and matched bytes.
     struct Bracket {
@@ -104,6 +117,8 @@ class GlobPattern {
       BitVector Bytes;
     };
     SmallVector<Bracket, 0> Brackets;
+    // Set while parsing if an unescaped '*' or '?' is present.
+    bool HasWildcard = false;
     SmallVector<char, 0> Pat;
   };
   SmallVector<SubGlobPattern, 1> SubGlobs;
diff --git a/llvm/lib/Support/GlobPattern.cpp b/llvm/lib/Support/GlobPattern.cpp
index ebaa08cba96aa..6f78a02af4606 100644
--- a/llvm/lib/Support/GlobPattern.cpp
+++ b/llvm/lib/Support/GlobPattern.cpp
@@ -182,6 +182,17 @@ static StringRef maxPlainSubstring(StringRef S, bool SlashAgnostic) {
   return Best;
 }
 
+// Writes S into Storage with its escaping backslashes removed.
+static void unescapePattern(StringRef S, SmallVectorImpl<char> &Storage) {
+  Storage.clear();
+  Storage.reserve(S.size());
+  for (size_t I = 0, E = S.size(); I != E; ++I) {
+    if (S[I] == '\\' && I + 1 != E)
+      ++I;
+    Storage.push_back(S[I]);
+  }
+}
+
 Expected<GlobPattern> GlobPattern::create(StringRef S,
                                           std::optional<size_t> MaxSubPatterns,
                                           bool SlashAgnostic) {
@@ -225,6 +236,23 @@ Expected<GlobPattern> GlobPattern::create(StringRef S,
   return Pat;
 }
 
+std::optional<StringRef>
+GlobPattern::asLiteral(SmallVectorImpl<char> &Storage) const {
+  // The prefix and suffix are metacharacter-free by construction, so whether
+  // this pattern denotes a single string is decided by the sub-patterns, which
+  // recorded it while parsing. No sub-pattern at all means there was no
+  // metacharacter; more than one means brace expansion produced a choice.
+  if (!SubGlobs.empty() &&
+      !(SubGlobs.size() == 1 && SubGlobs[0].isLiteral()))
+    return std::nullopt;
+
+  if (!Pattern.contains('\\'))
+    return Pattern;
+
+  unescapePattern(Pattern, Storage);
+  return StringRef(Storage.data(), Storage.size());
+}
+
 Expected<GlobPattern::SubGlobPattern>
 GlobPattern::SubGlobPattern::create(StringRef S, bool SlashAgnostic) {
   SubGlobPattern Pat;
@@ -260,6 +288,8 @@ GlobPattern::SubGlobPattern::create(StringRef S, bool SlashAgnostic) {
       if (++I == E)
         return make_error<StringError>("invalid glob pattern, stray '\\'",
                                        errc::invalid_argument);
+    } else if (S[I] == '*' || S[I] == '?') {
+      Pat.HasWildcard = true;
     }
   }
   return Pat;
diff --git a/llvm/unittests/Support/GlobPatternTest.cpp b/llvm/unittests/Support/GlobPatternTest.cpp
index 35423e37a3ae0..3be79476ca0c2 100644
--- a/llvm/unittests/Support/GlobPatternTest.cpp
+++ b/llvm/unittests/Support/GlobPatternTest.cpp
@@ -39,6 +39,63 @@ TEST_F(GlobPatternTest, Wildcard) {
   EXPECT_FALSE(Pat1->match(""));
 }
 
+TEST_F(GlobPatternTest, AsLiteral) {
+  SmallVector<char, 64> Storage;
+
+  // Plain literals, including characters that are only special in context.
+  // These need no unescaping, so the result aliases the pattern.
+  for (StringRef P : {"abc", "", "a]c", "a}c", "a,c"}) {
+    Expected<GlobPattern> Pat = GlobPattern::create(P);
+    ASSERT_TRUE((bool)Pat) << P;
+    std::optional<StringRef> Lit = Pat->asLiteral(Storage);
+    ASSERT_TRUE(Lit.has_value()) << P;
+    EXPECT_EQ(*Lit, P);
+    EXPECT_EQ(Lit->data(), P.data()) << P;
+  }
+
+  // Real metacharacters are not literals.
+  for (StringRef P : {"a*c", "a?c", "a[bc]d"}) {
+    Expected<GlobPattern> Pat = GlobPattern::create(P);
+    ASSERT_TRUE((bool)Pat) << P;
+    EXPECT_FALSE(Pat->asLiteral(Storage).has_value()) << P;
+  }
+
+  // Escaped metacharacters denote a single string, with escapes resolved.
+  Expected<GlobPattern> Star = GlobPattern::create("a\\*c");
+  ASSERT_TRUE((bool)Star);
+  ASSERT_TRUE(Star->asLiteral(Storage).has_value());
+  EXPECT_EQ(*Star->asLiteral(Storage), "a*c");
+  EXPECT_TRUE(Star->match("a*c"));
+  EXPECT_FALSE(Star->match("abc"));
+
+  // The motivating case: an Objective-C direct method symbol.
+  Expected<GlobPattern> Method = GlobPattern::create("-\\[C m\\]D");
+  ASSERT_TRUE((bool)Method);
+  ASSERT_TRUE(Method->asLiteral(Storage).has_value());
+  EXPECT_EQ(*Method->asLiteral(Storage), "-[C m]D");
+  EXPECT_TRUE(Method->match("-[C m]D"));
+
+  // An unescaped bracket expression is a character class, not this symbol.
+  Expected<GlobPattern> Class = GlobPattern::create("-[C m]D");
+  ASSERT_TRUE((bool)Class);
+  EXPECT_FALSE(Class->asLiteral(Storage).has_value());
+  EXPECT_FALSE(Class->match("-[C m]D"));
+
+  // '{' is a metacharacter only when brace expansion is enabled.
+  Expected<GlobPattern> NoBraces = GlobPattern::create("a{b,c}d");
+  ASSERT_TRUE((bool)NoBraces);
+  EXPECT_TRUE(NoBraces->asLiteral(Storage).has_value());
+  Expected<GlobPattern> Braces = GlobPattern::create("a{b,c}d", /*Max=*/1024);
+  ASSERT_TRUE((bool)Braces);
+  EXPECT_FALSE(Braces->asLiteral(Storage).has_value());
+
+  // An escaped backslash is a literal backslash.
+  Expected<GlobPattern> Backslash = GlobPattern::create("a\\\\c");
+  ASSERT_TRUE((bool)Backslash);
+  ASSERT_TRUE(Backslash->asLiteral(Storage).has_value());
+  EXPECT_EQ(*Backslash->asLiteral(Storage), "a\\c");
+}
+
 TEST_F(GlobPatternTest, Escape) {
   Expected<GlobPattern> Pat1 = GlobPattern::create("\\*");
   EXPECT_TRUE((bool)Pat1);

>From 52e49731d3720c80777f8118c64336c347fa7a7d Mon Sep 17 00:00:00 2001
From: Peter Rong <PeterRong at meta.com>
Date: Wed, 12 Aug 2026 10:51:48 -0700
Subject: [PATCH 2/4] format

---
 llvm/lib/Support/GlobPattern.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Support/GlobPattern.cpp b/llvm/lib/Support/GlobPattern.cpp
index 6f78a02af4606..8eee786c5f0d5 100644
--- a/llvm/lib/Support/GlobPattern.cpp
+++ b/llvm/lib/Support/GlobPattern.cpp
@@ -242,8 +242,7 @@ GlobPattern::asLiteral(SmallVectorImpl<char> &Storage) const {
   // this pattern denotes a single string is decided by the sub-patterns, which
   // recorded it while parsing. No sub-pattern at all means there was no
   // metacharacter; more than one means brace expansion produced a choice.
-  if (!SubGlobs.empty() &&
-      !(SubGlobs.size() == 1 && SubGlobs[0].isLiteral()))
+  if (!SubGlobs.empty() && !(SubGlobs.size() == 1 && SubGlobs[0].isLiteral()))
     return std::nullopt;
 
   if (!Pattern.contains('\\'))

>From a33ced549347fe2c03cdfcd6395e66a0d5cd1ec6 Mon Sep 17 00:00:00 2001
From: Peter Rong <PeterRong at meta.com>
Date: Wed, 12 Aug 2026 13:31:01 -0700
Subject: [PATCH 3/4] Address reviewer

---
 lld/MachO/Driver.cpp                       |  2 +-
 llvm/lib/Support/GlobPattern.cpp           | 33 +++++++-------
 llvm/unittests/Support/GlobPatternTest.cpp | 51 +++++++++++++++++++---
 3 files changed, 63 insertions(+), 23 deletions(-)

diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 2fa959eaf7e93..863c4e572bd9b 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1369,7 +1369,7 @@ void SymbolPatterns::insert(StringRef symbolName) {
   // A pattern that denotes a single string is kept as a literal: literals are
   // matched by hash lookup, and only literals seed the force-load of lazy
   // archive members below.
-  SmallVector<char, 128> storage;
+  SmallString<32> storage;
   if (std::optional<StringRef> literal = pattern->asLiteral(storage)) {
     literals.insert(CachedHashStringRef(saver().save(*literal)));
     return;
diff --git a/llvm/lib/Support/GlobPattern.cpp b/llvm/lib/Support/GlobPattern.cpp
index 8eee786c5f0d5..fc7b6c18ce295 100644
--- a/llvm/lib/Support/GlobPattern.cpp
+++ b/llvm/lib/Support/GlobPattern.cpp
@@ -182,17 +182,6 @@ static StringRef maxPlainSubstring(StringRef S, bool SlashAgnostic) {
   return Best;
 }
 
-// Writes S into Storage with its escaping backslashes removed.
-static void unescapePattern(StringRef S, SmallVectorImpl<char> &Storage) {
-  Storage.clear();
-  Storage.reserve(S.size());
-  for (size_t I = 0, E = S.size(); I != E; ++I) {
-    if (S[I] == '\\' && I + 1 != E)
-      ++I;
-    Storage.push_back(S[I]);
-  }
-}
-
 Expected<GlobPattern> GlobPattern::create(StringRef S,
                                           std::optional<size_t> MaxSubPatterns,
                                           bool SlashAgnostic) {
@@ -245,11 +234,25 @@ GlobPattern::asLiteral(SmallVectorImpl<char> &Storage) const {
   if (!SubGlobs.empty() && !(SubGlobs.size() == 1 && SubGlobs[0].isLiteral()))
     return std::nullopt;
 
-  if (!Pattern.contains('\\'))
-    return Pattern;
+  StringRef Literal = Pattern;
+  if (Pattern.contains('\\')) {
+    Storage.clear();
+    Storage.reserve(Pattern.size());
+    for (size_t I = 0, E = Pattern.size(); I != E; ++I) {
+      if (Pattern[I] == '\\' && I + 1 != E)
+        ++I;
+      Storage.push_back(Pattern[I]);
+    }
+    Literal = StringRef(Storage.data(), Storage.size());
+  }
+
+  // In slash-agnostic mode '/' and '\\' match each other, so a pattern holding
+  // either matches more than one string. A pattern with no sub-pattern cannot
+  // reach here holding one, as both are prefix metacharacters in that mode.
+  if (SlashAgnostic && Literal.find_first_of("/\\") != StringRef::npos)
+    return std::nullopt;
 
-  unescapePattern(Pattern, Storage);
-  return StringRef(Storage.data(), Storage.size());
+  return Literal;
 }
 
 Expected<GlobPattern::SubGlobPattern>
diff --git a/llvm/unittests/Support/GlobPatternTest.cpp b/llvm/unittests/Support/GlobPatternTest.cpp
index 3be79476ca0c2..22af2259c1880 100644
--- a/llvm/unittests/Support/GlobPatternTest.cpp
+++ b/llvm/unittests/Support/GlobPatternTest.cpp
@@ -50,7 +50,6 @@ TEST_F(GlobPatternTest, AsLiteral) {
     std::optional<StringRef> Lit = Pat->asLiteral(Storage);
     ASSERT_TRUE(Lit.has_value()) << P;
     EXPECT_EQ(*Lit, P);
-    EXPECT_EQ(Lit->data(), P.data()) << P;
   }
 
   // Real metacharacters are not literals.
@@ -63,16 +62,18 @@ TEST_F(GlobPatternTest, AsLiteral) {
   // Escaped metacharacters denote a single string, with escapes resolved.
   Expected<GlobPattern> Star = GlobPattern::create("a\\*c");
   ASSERT_TRUE((bool)Star);
-  ASSERT_TRUE(Star->asLiteral(Storage).has_value());
-  EXPECT_EQ(*Star->asLiteral(Storage), "a*c");
+  auto StarLit = Star->asLiteral(Storage);
+  ASSERT_TRUE(StarLit.has_value());
+  EXPECT_EQ(*StarLit, "a*c");
   EXPECT_TRUE(Star->match("a*c"));
   EXPECT_FALSE(Star->match("abc"));
 
   // The motivating case: an Objective-C direct method symbol.
   Expected<GlobPattern> Method = GlobPattern::create("-\\[C m\\]D");
   ASSERT_TRUE((bool)Method);
-  ASSERT_TRUE(Method->asLiteral(Storage).has_value());
-  EXPECT_EQ(*Method->asLiteral(Storage), "-[C m]D");
+  auto MethodLit = Method->asLiteral(Storage);
+  ASSERT_TRUE(MethodLit.has_value());
+  EXPECT_EQ(*MethodLit, "-[C m]D");
   EXPECT_TRUE(Method->match("-[C m]D"));
 
   // An unescaped bracket expression is a character class, not this symbol.
@@ -92,8 +93,44 @@ TEST_F(GlobPatternTest, AsLiteral) {
   // An escaped backslash is a literal backslash.
   Expected<GlobPattern> Backslash = GlobPattern::create("a\\\\c");
   ASSERT_TRUE((bool)Backslash);
-  ASSERT_TRUE(Backslash->asLiteral(Storage).has_value());
-  EXPECT_EQ(*Backslash->asLiteral(Storage), "a\\c");
+  auto BackslashLit = Backslash->asLiteral(Storage);
+  ASSERT_TRUE(BackslashLit.has_value());
+  EXPECT_EQ(*BackslashLit, "a\\c");
+}
+
+TEST_F(GlobPatternTest, AsLiteralSlashAgnostic) {
+  SmallString<64> Storage;
+
+  // Without slash-agnostic matching a separator is an ordinary character.
+  Expected<GlobPattern> Plain = GlobPattern::create("a/b");
+  ASSERT_TRUE((bool)Plain);
+  auto PlainLit = Plain->asLiteral(Storage);
+  ASSERT_TRUE(PlainLit.has_value());
+  EXPECT_EQ(*PlainLit, "a/b");
+
+  // With it, '/' also matches '\\', so this denotes two strings, not one.
+  Expected<GlobPattern> Slash =
+      GlobPattern::create("a/b", std::nullopt, /*SlashAgnostic=*/true);
+  ASSERT_TRUE((bool)Slash);
+  EXPECT_TRUE(Slash->match("a/b"));
+  EXPECT_TRUE(Slash->match("a\\b"));
+  EXPECT_FALSE(Slash->asLiteral(Storage).has_value());
+
+  // An escaped backslash resolves to a separator, so likewise.
+  Expected<GlobPattern> Backslash =
+      GlobPattern::create("a\\\\b", std::nullopt, /*SlashAgnostic=*/true);
+  ASSERT_TRUE((bool)Backslash);
+  EXPECT_TRUE(Backslash->match("a\\b"));
+  EXPECT_TRUE(Backslash->match("a/b"));
+  EXPECT_FALSE(Backslash->asLiteral(Storage).has_value());
+
+  // Escaping a non-separator is still a literal in slash-agnostic mode.
+  Expected<GlobPattern> Star =
+      GlobPattern::create("a\\*b", std::nullopt, /*SlashAgnostic=*/true);
+  ASSERT_TRUE((bool)Star);
+  auto StarLit = Star->asLiteral(Storage);
+  ASSERT_TRUE(StarLit.has_value());
+  EXPECT_EQ(*StarLit, "a*b");
 }
 
 TEST_F(GlobPatternTest, Escape) {

>From e451b0131e24a88200d775b31da3a24c95c7ce96 Mon Sep 17 00:00:00 2001
From: Peter Rong <peterrong96 at gmail.com>
Date: Mon, 24 Aug 2026 16:49:50 -0700
Subject: [PATCH 4/4] Update lld/MachO/Driver.cpp

Co-authored-by: Ellis Hoag <ellis.sparky.hoag at gmail.com>
---
 lld/MachO/Driver.cpp | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 863c4e572bd9b..a3660a20bd9b3 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1361,11 +1361,7 @@ void SymbolPatterns::clear() {
 
 void SymbolPatterns::insert(StringRef symbolName) {
   Expected<GlobPattern> pattern = GlobPattern::create(symbolName);
-  if (!pattern) {
-    llvm::consumeError(pattern.takeError());
-    error("invalid symbol-name pattern: " + symbolName);
-    return;
-  }
+  checkError(pattern.takeError());
   // A pattern that denotes a single string is kept as a literal: literals are
   // matched by hash lookup, and only literals seed the force-load of lazy
   // archive members below.



More information about the llvm-commits mailing list