https://github.com/StoeckOverflow created 
https://github.com/llvm/llvm-project/pull/205307

This PR teaches Sema to apply function-like `Where.Parameters` selectors for 
API notes.

It builds on #204147 by using the serialized `Where.Parameters` selector keys 
in Sema. For each `FunctionDecl` / `CXXMethodDecl`, Sema derives an exact 
parameter selector from the declaration’s `FunctionProtoType`. Broad name-only 
API notes lookup still runs first, preserving existing behavior. If Clang can 
form a parameter selector, Sema then performs an exact selector lookup and 
applies that result second, allowing overload-specific notes to refine 
same-name broad notes.

Tests:
- Adds end-to-end module APINotes Sema coverage (`.apinotes` source -> binary 
APINotes -> reader lookup -> Sema matching -> AST result)
- Covers core matching behavior for global functions and C++ methods, including 
same-name overloads, exact empty selectors, broad-plus-exact coexistence and 
mismatched selectors
- Covers important edge cases: default arguments, static methods, alias 
spellings remaining non-canonicalized, by-value `const`, namespaced functions, 
and overloaded operators.

This PR does not add duplicate-selector or unmatched-selector diagnostics. 
Those remain for a follow-up diagnostics PR.

**Note**: this PR is stacked on top of #204147, which has not merged yet. Until 
that PR gets merged, GitHub will also show the serialization changes in this 
diff. The changes specific to this PR are contained in the top commit, 
ca9bc2b80e6beb3bf41d3f9914a4e41defaceb2b (`[APINotes] Apply Where.Parameters 
selectors in Sema`).

Reviewers: @Xazax-hun @j-hui @egorzhdan

>From 9a0d376597fe0ce04f5af1350ecced91679af5dd Mon Sep 17 00:00:00 2001
From: stoeckoverflow <[email protected]>
Date: Tue, 16 Jun 2026 14:08:09 +0200
Subject: [PATCH 1/3] [APINotes] Serialize function-like Where.Parameters

---
 clang/include/clang/APINotes/APINotesReader.h |  19 +++
 clang/include/clang/APINotes/APINotesWriter.h |  20 ++++
 clang/lib/APINotes/APINotesFormat.h           |  70 ++++++++++-
 clang/lib/APINotes/APINotesReader.cpp         | 112 +++++++++++++++---
 clang/lib/APINotes/APINotesWriter.cpp         |  95 +++++++++++----
 clang/lib/APINotes/APINotesYAMLCompiler.cpp   |  40 +++++--
 .../APINotes.apinotes                         |   9 +-
 .../WhereParametersConvertDiag.h              |   2 +
 .../APINotes.apinotes                         |  12 ++
 .../WhereParametersConvertDiag.h              |  10 ++
 .../where-parameters-convert-diags.cpp        |   5 +-
 11 files changed, 341 insertions(+), 53 deletions(-)
 create mode 100644 
clang/test/APINotes/Inputs/WhereParametersEmptyWhereDiag/APINotes.apinotes
 create mode 100644 
clang/test/APINotes/Inputs/WhereParametersEmptyWhereDiag/WhereParametersConvertDiag.h

diff --git a/clang/include/clang/APINotes/APINotesReader.h 
b/clang/include/clang/APINotes/APINotesReader.h
index 875c314b284c1..c5e32dc6a51c7 100644
--- a/clang/include/clang/APINotes/APINotesReader.h
+++ b/clang/include/clang/APINotes/APINotesReader.h
@@ -16,10 +16,12 @@
 #define LLVM_CLANG_APINOTES_READER_H
 
 #include "clang/APINotes/Types.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/VersionTuple.h"
 #include <memory>
+#include <optional>
 
 namespace clang {
 namespace api_notes {
@@ -159,6 +161,14 @@ class APINotesReader {
   VersionedInfo<CXXMethodInfo> lookupCXXMethod(ContextID CtxID,
                                                llvm::StringRef Name);
 
+  /// Look for information regarding the given C++ method with an optional
+  /// parameter selector. Passing std::nullopt uses the name-only key, an empty
+  /// parameter list uses an exact zero-parameter key, and a non-empty list 
uses
+  /// an exact ordered parameter key.
+  VersionedInfo<CXXMethodInfo>
+  lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
+                  std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters);
+
   /// Look for information regarding the given global variable.
   ///
   /// \param Name The name of the global variable.
@@ -177,6 +187,15 @@ class APINotesReader {
   lookupGlobalFunction(llvm::StringRef Name,
                        std::optional<Context> Ctx = std::nullopt);
 
+  /// Look for information regarding the given global function with an optional
+  /// parameter selector. Passing std::nullopt uses the name-only key, an empty
+  /// parameter list uses an exact zero-parameter key, and a non-empty list 
uses
+  /// an exact ordered parameter key.
+  VersionedInfo<GlobalFunctionInfo> lookupGlobalFunction(
+      llvm::StringRef Name,
+      std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
+      std::optional<Context> Ctx = std::nullopt);
+
   /// Look for information regarding the given enumerator.
   ///
   /// \param Name The name of the enumerator.
diff --git a/clang/include/clang/APINotes/APINotesWriter.h 
b/clang/include/clang/APINotes/APINotesWriter.h
index 3cc16c3d959fa..5abea950aac14 100644
--- a/clang/include/clang/APINotes/APINotesWriter.h
+++ b/clang/include/clang/APINotes/APINotesWriter.h
@@ -16,11 +16,13 @@
 #define LLVM_CLANG_APINOTES_WRITER_H
 
 #include "clang/APINotes/Types.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/VersionTuple.h"
 #include "llvm/Support/raw_ostream.h"
 
 #include <memory>
+#include <optional>
 
 namespace clang {
 class FileEntry;
@@ -86,6 +88,14 @@ class APINotesWriter {
   void addCXXMethod(ContextID CtxID, llvm::StringRef Name,
                     const CXXMethodInfo &Info, llvm::VersionTuple 
SwiftVersion);
 
+  /// Add information about a C++ method with an optional parameter selector.
+  /// Passing std::nullopt uses the name-only key, an empty parameter list uses
+  /// an exact zero-parameter key, and a non-empty list uses an exact ordered
+  /// parameter key.
+  void addCXXMethod(ContextID CtxID, llvm::StringRef Name,
+                    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
+                    const CXXMethodInfo &Info, llvm::VersionTuple 
SwiftVersion);
+
   /// Add information about a specific C record field.
   ///
   /// \param CtxID The context in which this field resides, i.e. a C/C++ tag.
@@ -110,6 +120,16 @@ class APINotesWriter {
                          const GlobalFunctionInfo &Info,
                          llvm::VersionTuple SwiftVersion);
 
+  /// Add information about a global function with an optional parameter
+  /// selector. Passing std::nullopt uses the name-only key, an empty parameter
+  /// list uses an exact zero-parameter key, and a non-empty list uses an exact
+  /// ordered parameter key.
+  void
+  addGlobalFunction(std::optional<Context> Ctx, llvm::StringRef Name,
+                    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
+                    const GlobalFunctionInfo &Info,
+                    llvm::VersionTuple SwiftVersion);
+
   /// Add information about an enumerator.
   ///
   /// \param Name The name of this enumerator.
diff --git a/clang/lib/APINotes/APINotesFormat.h 
b/clang/lib/APINotes/APINotesFormat.h
index 5679ae39e9900..6f78ede4f608f 100644
--- a/clang/lib/APINotes/APINotesFormat.h
+++ b/clang/lib/APINotes/APINotesFormat.h
@@ -11,8 +11,12 @@
 
 #include "clang/APINotes/Types.h"
 #include "llvm/ADT/PointerEmbeddedInt.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/Bitcode/BitcodeConvenience.h"
 
+#include <optional>
+#include <utility>
+
 namespace clang {
 namespace api_notes {
 /// Magic number for API notes files.
@@ -24,8 +28,9 @@ const uint16_t VERSION_MAJOR = 0;
 /// API notes file minor version number.
 ///
 /// When the format changes IN ANY WAY, this number should be incremented.
-const uint16_t VERSION_MINOR = 40; // 39 for BoundsSafety;
+const uint16_t VERSION_MINOR = 41; // 39 for BoundsSafety;
                                    // 40 for UnsafeBufferUsageAttr
+                                   // 41 for FunctionTableKey parameters
 
 const uint8_t kSwiftConforms = 1;
 const uint8_t kSwiftDoesNotConform = 2;
@@ -354,6 +359,57 @@ inline bool operator==(const SingleDeclTableKey &lhs,
   return lhs.parentContextID == rhs.parentContextID && lhs.nameID == 
rhs.nameID;
 }
 
+/// A stored C or C++ function declaration, represented by the ID of its parent
+/// context, the name of the declaration, and optional exact parameter types.
+constexpr uint8_t FunctionKeyHasParameterSelector = 0x01;
+constexpr unsigned FunctionTableKeyBaseLength =
+    sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint16_t);
+
+struct FunctionTableKey {
+  uint32_t parentContextID;
+  uint32_t nameID;
+  std::optional<llvm::SmallVector<IdentifierID, 2>> parameterTypeIDs;
+
+  FunctionTableKey() : parentContextID(-1), nameID(-1) {}
+
+  FunctionTableKey(uint32_t ParentContextID, uint32_t NameID)
+      : parentContextID(ParentContextID), nameID(NameID) {}
+
+  FunctionTableKey(uint32_t ParentContextID, uint32_t NameID,
+                   llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs)
+      : parentContextID(ParentContextID), nameID(NameID),
+        parameterTypeIDs(std::move(ParameterTypeIDs)) {}
+
+  FunctionTableKey(std::optional<Context> ParentCtx, IdentifierID NameID)
+      : parentContextID(ParentCtx ? ParentCtx->id.Value
+                                  : static_cast<uint32_t>(-1)),
+        nameID(NameID) {}
+
+  FunctionTableKey(std::optional<Context> ParentCtx, IdentifierID NameID,
+                   llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs)
+      : parentContextID(ParentCtx ? ParentCtx->id.Value
+                                  : static_cast<uint32_t>(-1)),
+        nameID(NameID), parameterTypeIDs(std::move(ParameterTypeIDs)) {}
+
+  llvm::hash_code hashValue() const {
+    auto Hash = llvm::hash_combine(parentContextID, nameID,
+                                   static_cast<bool>(parameterTypeIDs));
+    if (parameterTypeIDs) {
+      Hash = llvm::hash_combine(Hash, parameterTypeIDs->size());
+      for (IdentifierID TypeID : *parameterTypeIDs)
+        Hash = llvm::hash_combine(Hash, static_cast<unsigned>(TypeID));
+    }
+    return Hash;
+  }
+};
+
+inline bool operator==(const FunctionTableKey &lhs,
+                       const FunctionTableKey &rhs) {
+  return lhs.parentContextID == rhs.parentContextID &&
+         lhs.nameID == rhs.nameID &&
+         lhs.parameterTypeIDs == rhs.parameterTypeIDs;
+}
+
 } // namespace api_notes
 } // namespace clang
 
@@ -401,6 +457,18 @@ template <> struct 
DenseMapInfo<clang::api_notes::SingleDeclTableKey> {
   }
 };
 
+template <> struct DenseMapInfo<clang::api_notes::FunctionTableKey> {
+  static unsigned
+  getHashValue(const clang::api_notes::FunctionTableKey &value) {
+    return value.hashValue();
+  }
+
+  static bool isEqual(const clang::api_notes::FunctionTableKey &lhs,
+                      const clang::api_notes::FunctionTableKey &rhs) {
+    return lhs == rhs;
+  }
+};
+
 } // namespace llvm
 
 #endif
diff --git a/clang/lib/APINotes/APINotesReader.cpp 
b/clang/lib/APINotes/APINotesReader.cpp
index 7713e47cba3a9..5ac172b369444 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -46,6 +46,38 @@ llvm::VersionTuple ReadVersionTuple(const uint8_t *&Data) {
   return llvm::VersionTuple(Major, Minor, Subminor, Build);
 }
 
+static FunctionTableKey readFunctionTableKey(const uint8_t *Data,
+                                             unsigned Length) {
+  assert(Length >= FunctionTableKeyBaseLength &&
+         "Unexpected function table key length");
+
+  auto CtxID = endian::readNext<uint32_t, llvm::endianness::little>(Data);
+  auto NameID = endian::readNext<uint32_t, llvm::endianness::little>(Data);
+  uint8_t FunctionKeyFlags =
+      endian::readNext<uint8_t, llvm::endianness::little>(Data);
+  auto ParameterCount =
+      endian::readNext<uint16_t, llvm::endianness::little>(Data);
+
+  assert(Length ==
+             FunctionTableKeyBaseLength + ParameterCount * sizeof(uint32_t) &&
+         "Unexpected function table key length");
+
+  llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs;
+  ParameterTypeIDs.reserve(ParameterCount);
+  for (unsigned I = 0; I != ParameterCount; ++I)
+    ParameterTypeIDs.push_back(
+        endian::readNext<uint32_t, llvm::endianness::little>(Data));
+
+  assert((FunctionKeyFlags & ~FunctionKeyHasParameterSelector) == 0 &&
+         "Unexpected function table key flags");
+  if (FunctionKeyFlags & FunctionKeyHasParameterSelector)
+    return {CtxID, NameID, std::move(ParameterTypeIDs)};
+
+  assert(ParameterTypeIDs.empty() &&
+         "Broad function table key should not store parameters");
+  return {CtxID, NameID};
+}
+
 /// An on-disk hash table whose data is versioned based on the Swift version.
 template <typename Derived, typename KeyType, typename UnversionedDataType>
 class VersionedTableInfo {
@@ -527,13 +559,11 @@ class GlobalVariableTableInfo
 
 /// Used to deserialize the on-disk global function table.
 class GlobalFunctionTableInfo
-    : public VersionedTableInfo<GlobalFunctionTableInfo, SingleDeclTableKey,
+    : public VersionedTableInfo<GlobalFunctionTableInfo, FunctionTableKey,
                                 GlobalFunctionInfo> {
 public:
   static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) {
-    auto CtxID = endian::readNext<uint32_t, llvm::endianness::little>(Data);
-    auto NameID = endian::readNext<uint32_t, llvm::endianness::little>(Data);
-    return {CtxID, NameID};
+    return readFunctionTableKey(Data, Length);
   }
 
   hash_value_type ComputeHash(internal_key_type Key) {
@@ -550,13 +580,11 @@ class GlobalFunctionTableInfo
 
 /// Used to deserialize the on-disk C++ method table.
 class CXXMethodTableInfo
-    : public VersionedTableInfo<CXXMethodTableInfo, SingleDeclTableKey,
+    : public VersionedTableInfo<CXXMethodTableInfo, FunctionTableKey,
                                 CXXMethodInfo> {
 public:
   static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) {
-    auto CtxID = endian::readNext<uint32_t, llvm::endianness::little>(Data);
-    auto NameID = endian::readNext<uint32_t, llvm::endianness::little>(Data);
-    return {CtxID, NameID};
+    return readFunctionTableKey(Data, Length);
   }
 
   hash_value_type ComputeHash(internal_key_type Key) {
@@ -827,6 +855,13 @@ class APINotesReader::Implementation {
                                     llvm::SmallVectorImpl<uint64_t> &Scratch);
   llvm::Error readGlobalVariableBlock(llvm::BitstreamCursor &Cursor,
                                       llvm::SmallVectorImpl<uint64_t> 
&Scratch);
+  std::optional<FunctionTableKey>
+  getFunctionKey(uint32_t ParentContextID, llvm::StringRef Name,
+                 std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters);
+  std::optional<FunctionTableKey>
+  getFunctionKey(std::optional<Context> ParentContext, llvm::StringRef Name,
+                 std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters);
+
   llvm::Error readGlobalFunctionBlock(llvm::BitstreamCursor &Cursor,
                                       llvm::SmallVectorImpl<uint64_t> 
&Scratch);
   llvm::Error readEnumConstantBlock(llvm::BitstreamCursor &Cursor,
@@ -852,6 +887,36 @@ 
APINotesReader::Implementation::getIdentifier(llvm::StringRef Str) {
   return *Known;
 }
 
+std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
+    uint32_t ParentContextID, llvm::StringRef Name,
+    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters) {
+  std::optional<IdentifierID> NameID = getIdentifier(Name);
+  if (!NameID)
+    return std::nullopt;
+
+  if (!Parameters)
+    return FunctionTableKey(ParentContextID, *NameID);
+
+  llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs;
+  ParameterTypeIDs.reserve(Parameters->size());
+  for (llvm::StringRef Parameter : *Parameters) {
+    std::optional<IdentifierID> ParameterID = getIdentifier(Parameter);
+    if (!ParameterID)
+      return std::nullopt;
+    ParameterTypeIDs.push_back(*ParameterID);
+  }
+  return FunctionTableKey(ParentContextID, *NameID,
+                          std::move(ParameterTypeIDs));
+}
+
+std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
+    std::optional<Context> ParentContext, llvm::StringRef Name,
+    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters) {
+  uint32_t ParentContextID =
+      ParentContext ? ParentContext->id.Value : static_cast<uint32_t>(-1);
+  return getFunctionKey(ParentContextID, Name, Parameters);
+}
+
 std::optional<SelectorID>
 APINotesReader::Implementation::getSelector(ObjCSelectorRef Selector) {
   if (!ObjCSelectorTable || !IdentifierTable)
@@ -2268,15 +2333,22 @@ auto APINotesReader::lookupField(ContextID CtxID, 
llvm::StringRef Name)
 
 auto APINotesReader::lookupCXXMethod(ContextID CtxID, llvm::StringRef Name)
     -> VersionedInfo<CXXMethodInfo> {
+  return lookupCXXMethod(CtxID, Name, std::nullopt);
+}
+
+auto APINotesReader::lookupCXXMethod(
+    ContextID CtxID, llvm::StringRef Name,
+    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters)
+    -> VersionedInfo<CXXMethodInfo> {
   if (!Implementation->CXXMethodTable)
     return std::nullopt;
 
-  std::optional<IdentifierID> NameID = Implementation->getIdentifier(Name);
-  if (!NameID)
+  std::optional<FunctionTableKey> Key =
+      Implementation->getFunctionKey(CtxID.Value, Name, Parameters);
+  if (!Key)
     return std::nullopt;
 
-  auto Known = Implementation->CXXMethodTable->find(
-      SingleDeclTableKey(CtxID.Value, *NameID));
+  auto Known = Implementation->CXXMethodTable->find(*Key);
   if (Known == Implementation->CXXMethodTable->end())
     return std::nullopt;
 
@@ -2305,16 +2377,22 @@ auto 
APINotesReader::lookupGlobalVariable(llvm::StringRef Name,
 auto APINotesReader::lookupGlobalFunction(llvm::StringRef Name,
                                           std::optional<Context> Ctx)
     -> VersionedInfo<GlobalFunctionInfo> {
+  return lookupGlobalFunction(Name, std::nullopt, Ctx);
+}
+
+auto APINotesReader::lookupGlobalFunction(
+    llvm::StringRef Name,
+    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
+    std::optional<Context> Ctx) -> VersionedInfo<GlobalFunctionInfo> {
   if (!Implementation->GlobalFunctionTable)
     return std::nullopt;
 
-  std::optional<IdentifierID> NameID = Implementation->getIdentifier(Name);
-  if (!NameID)
+  std::optional<FunctionTableKey> Key =
+      Implementation->getFunctionKey(Ctx, Name, Parameters);
+  if (!Key)
     return std::nullopt;
 
-  SingleDeclTableKey Key(Ctx, *NameID);
-
-  auto Known = Implementation->GlobalFunctionTable->find(Key);
+  auto Known = Implementation->GlobalFunctionTable->find(*Key);
   if (Known == Implementation->GlobalFunctionTable->end())
     return std::nullopt;
 
diff --git a/clang/lib/APINotes/APINotesWriter.cpp 
b/clang/lib/APINotes/APINotesWriter.cpp
index 61150669d8329..48abeced839fc 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -82,8 +82,8 @@ class APINotesWriter::Implementation {
 
   /// Information about C++ methods.
   ///
-  /// Indexed by the context ID and name ID.
-  llvm::DenseMap<SingleDeclTableKey,
+  /// Indexed by the context ID, name ID, and optional parameter selector.
+  llvm::DenseMap<FunctionTableKey,
                  llvm::SmallVector<std::pair<VersionTuple, CXXMethodInfo>, 1>>
       CXXMethods;
 
@@ -100,9 +100,9 @@ class APINotesWriter::Implementation {
 
   /// Information about global functions.
   ///
-  /// Indexed by the context ID, identifier ID.
+  /// Indexed by the context ID, identifier ID, and optional parameter 
selector.
   llvm::DenseMap<
-      SingleDeclTableKey,
+      FunctionTableKey,
       llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>, 1>>
       GlobalFunctions;
 
@@ -137,6 +137,29 @@ class APINotesWriter::Implementation {
         .first->second;
   }
 
+  FunctionTableKey
+  getFunctionKey(uint32_t ParentContextID, StringRef Name,
+                 std::optional<ArrayRef<StringRef>> Parameters = std::nullopt) 
{
+    IdentifierID NameID = getIdentifier(Name);
+    if (!Parameters)
+      return FunctionTableKey(ParentContextID, NameID);
+
+    llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs;
+    ParameterTypeIDs.reserve(Parameters->size());
+    for (StringRef Parameter : *Parameters)
+      ParameterTypeIDs.push_back(getIdentifier(Parameter));
+    return FunctionTableKey(ParentContextID, NameID,
+                            std::move(ParameterTypeIDs));
+  }
+
+  FunctionTableKey
+  getFunctionKey(std::optional<Context> ParentContext, StringRef Name,
+                 std::optional<ArrayRef<StringRef>> Parameters = std::nullopt) 
{
+    uint32_t ParentContextID =
+        ParentContext ? ParentContext->id.Value : static_cast<uint32_t>(-1);
+    return getFunctionKey(ParentContextID, Name, Parameters);
+  }
+
   /// Retrieve the ID for the given selector.
   SelectorID getSelector(ObjCSelectorRef SelectorRef) {
     // Translate the selector reference into a stored selector.
@@ -387,7 +410,9 @@ class ContextIDTableInfo {
 
 /// Localized helper to make a type dependent, thwarting template argument
 /// deduction.
-template <typename T> struct MakeDependent { typedef T Type; };
+template <typename T> struct MakeDependent {
+  typedef T Type;
+};
 
 /// Retrieve the serialized size of the given VersionTuple, for use in
 /// on-disk hash tables.
@@ -465,6 +490,25 @@ void emitVersionedInfo(
   }
 }
 
+static unsigned getFunctionTableKeyLength(const FunctionTableKey &Key) {
+  return FunctionTableKeyBaseLength +
+         (Key.parameterTypeIDs ? Key.parameterTypeIDs->size() * 
sizeof(uint32_t)
+                               : 0);
+}
+
+static void emitFunctionTableKey(raw_ostream &OS, const FunctionTableKey &Key) 
{
+  llvm::support::endian::Writer writer(OS, llvm::endianness::little);
+  writer.write<uint32_t>(Key.parentContextID);
+  writer.write<uint32_t>(Key.nameID);
+  writer.write<uint8_t>(Key.parameterTypeIDs ? FunctionKeyHasParameterSelector
+                                             : 0);
+  writer.write<uint16_t>(Key.parameterTypeIDs ? Key.parameterTypeIDs->size()
+                                              : 0);
+  if (Key.parameterTypeIDs)
+    for (IdentifierID TypeID : *Key.parameterTypeIDs)
+      writer.write<uint32_t>(TypeID);
+}
+
 /// On-disk hash table info key base for handling versioned data.
 template <typename Derived, typename KeyType, typename UnversionedDataType>
 class VersionedTableInfo {
@@ -801,17 +845,15 @@ class ObjCMethodTableInfo
 
 /// Used to serialize the on-disk C++ method table.
 class CXXMethodTableInfo
-    : public VersionedTableInfo<CXXMethodTableInfo, SingleDeclTableKey,
+    : public VersionedTableInfo<CXXMethodTableInfo, FunctionTableKey,
                                 CXXMethodInfo> {
 public:
-  unsigned getKeyLength(key_type_ref) {
-    return sizeof(uint32_t) + sizeof(uint32_t);
+  unsigned getKeyLength(key_type_ref Key) {
+    return getFunctionTableKeyLength(Key);
   }
 
   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
-    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
-    writer.write<uint32_t>(Key.parentContextID);
-    writer.write<uint32_t>(Key.nameID);
+    emitFunctionTableKey(OS, Key);
   }
 
   hash_value_type ComputeHash(key_type_ref key) {
@@ -1176,17 +1218,15 @@ void emitFunctionInfo(raw_ostream &OS, const 
FunctionInfo &FI) {
 
 /// Used to serialize the on-disk global function table.
 class GlobalFunctionTableInfo
-    : public VersionedTableInfo<GlobalFunctionTableInfo, SingleDeclTableKey,
+    : public VersionedTableInfo<GlobalFunctionTableInfo, FunctionTableKey,
                                 GlobalFunctionInfo> {
 public:
-  unsigned getKeyLength(key_type_ref) {
-    return sizeof(uint32_t) + sizeof(uint32_t);
+  unsigned getKeyLength(key_type_ref Key) {
+    return getFunctionTableKeyLength(Key);
   }
 
   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
-    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
-    writer.write<uint32_t>(Key.parentContextID);
-    writer.write<uint32_t>(Key.nameID);
+    emitFunctionTableKey(OS, Key);
   }
 
   hash_value_type ComputeHash(key_type_ref Key) {
@@ -1567,8 +1607,15 @@ void APINotesWriter::addObjCMethod(ContextID CtxID, 
ObjCSelectorRef Selector,
 void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,
                                   const CXXMethodInfo &Info,
                                   VersionTuple SwiftVersion) {
-  IdentifierID NameID = Implementation->getIdentifier(Name);
-  SingleDeclTableKey Key(CtxID.Value, NameID);
+  addCXXMethod(CtxID, Name, std::nullopt, Info, SwiftVersion);
+}
+
+void APINotesWriter::addCXXMethod(
+    ContextID CtxID, llvm::StringRef Name,
+    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
+    const CXXMethodInfo &Info, VersionTuple SwiftVersion) {
+  FunctionTableKey Key =
+      Implementation->getFunctionKey(CtxID.Value, Name, Parameters);
   Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
 }
 
@@ -1593,8 +1640,14 @@ void 
APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
                                        llvm::StringRef Name,
                                        const GlobalFunctionInfo &Info,
                                        VersionTuple SwiftVersion) {
-  IdentifierID NameID = Implementation->getIdentifier(Name);
-  SingleDeclTableKey Key(Ctx, NameID);
+  addGlobalFunction(Ctx, Name, std::nullopt, Info, SwiftVersion);
+}
+
+void APINotesWriter::addGlobalFunction(
+    std::optional<Context> Ctx, llvm::StringRef Name,
+    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
+    const GlobalFunctionInfo &Info, VersionTuple SwiftVersion) {
+  FunctionTableKey Key = Implementation->getFunctionKey(Ctx, Name, Parameters);
   Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
 }
 
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp 
b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index e17549f33d219..d02cd3a3f3c56 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -1043,6 +1043,22 @@ class YAMLConverter {
                          TheNamespace.Items, SwiftVersion);
   }
 
+  bool getWhereParameters(
+      const Function &Function,
+      std::optional<llvm::ArrayRef<llvm::StringRef>> &WhereParameters) {
+    WhereParameters = std::nullopt;
+    if (!Function.Where)
+      return true;
+
+    if (!Function.Where->Parameters) {
+      emitError("'Where' requires 'Parameters'");
+      return false;
+    }
+    WhereParameters =
+        llvm::ArrayRef<llvm::StringRef>(*Function.Where->Parameters);
+    return true;
+  }
+
   template <typename FuncOrMethodInfo>
   void convertFunction(const Function &Function, FuncOrMethodInfo &FI) {
     convertAvailability(Function.Availability, FI, Function.Name);
@@ -1151,14 +1167,14 @@ class YAMLConverter {
     }
 
     for (const auto &CXXMethod : T.Methods) {
-      if (CXXMethod.Where) {
-        emitError("'Where' is not supported by binary API notes yet");
+      std::optional<llvm::ArrayRef<llvm::StringRef>> WhereParameters;
+      if (!getWhereParameters(CXXMethod, WhereParameters))
         continue;
-      }
 
       CXXMethodInfo MI;
       convertFunction(CXXMethod, MI);
-      Writer.addCXXMethod(TagCtxID, CXXMethod.Name, MI, SwiftVersion);
+      Writer.addCXXMethod(TagCtxID, CXXMethod.Name, WhereParameters, MI,
+                          SwiftVersion);
     }
 
     // Convert nested tags.
@@ -1227,15 +1243,16 @@ class YAMLConverter {
     }
 
     // Write all global functions.
-    llvm::StringSet<> KnownFunctions;
+    llvm::StringSet<> KnownNameOnlyFunctions;
     for (const auto &Function : TLItems.Functions) {
-      if (Function.Where) {
-        emitError("'Where' is not supported by binary API notes yet");
+      std::optional<llvm::ArrayRef<llvm::StringRef>> WhereParameters;
+      if (!getWhereParameters(Function, WhereParameters))
         continue;
-      }
 
-      // Check for duplicate global functions.
-      if (!KnownFunctions.insert(Function.Name).second) {
+      // Check for duplicate name-only global functions. Selector-aware
+      // duplicate diagnostics are handled by a later overload-matching PR.
+      if (!WhereParameters &&
+          !KnownNameOnlyFunctions.insert(Function.Name).second) {
         emitError(llvm::Twine("multiple definitions of global function '") +
                   Function.Name + "'");
         continue;
@@ -1243,7 +1260,8 @@ class YAMLConverter {
 
       GlobalFunctionInfo GFI;
       convertFunction(Function, GFI);
-      Writer.addGlobalFunction(Ctx, Function.Name, GFI, SwiftVersion);
+      Writer.addGlobalFunction(Ctx, Function.Name, WhereParameters, GFI,
+                               SwiftVersion);
     }
 
     // Write all enumerators.
diff --git 
a/clang/test/APINotes/Inputs/WhereParametersConvertDiag/APINotes.apinotes 
b/clang/test/APINotes/Inputs/WhereParametersConvertDiag/APINotes.apinotes
index c1eca20d96e89..f6451eab24544 100644
--- a/clang/test/APINotes/Inputs/WhereParametersConvertDiag/APINotes.apinotes
+++ b/clang/test/APINotes/Inputs/WhereParametersConvertDiag/APINotes.apinotes
@@ -1,8 +1,15 @@
 ---
 Name: WhereParametersConvertDiag
+Functions:
+- Name: makeWidget
+  Where:
+    Parameters:
+      - int
+  SwiftName: makeWidget(_:)
 Tags:
 - Name: Widget
   Methods:
   - Name: reset
-    Where: {}
+    Where:
+      Parameters: []
     SwiftName: reset()
diff --git 
a/clang/test/APINotes/Inputs/WhereParametersConvertDiag/WhereParametersConvertDiag.h
 
b/clang/test/APINotes/Inputs/WhereParametersConvertDiag/WhereParametersConvertDiag.h
index 32dc081bfc036..6807ce279f99a 100644
--- 
a/clang/test/APINotes/Inputs/WhereParametersConvertDiag/WhereParametersConvertDiag.h
+++ 
b/clang/test/APINotes/Inputs/WhereParametersConvertDiag/WhereParametersConvertDiag.h
@@ -1,6 +1,8 @@
 #ifndef WHERE_PARAMETERS_CONVERT_DIAG_H
 #define WHERE_PARAMETERS_CONVERT_DIAG_H
 
+void makeWidget(int);
+
 struct Widget {
   void reset();
 };
diff --git 
a/clang/test/APINotes/Inputs/WhereParametersEmptyWhereDiag/APINotes.apinotes 
b/clang/test/APINotes/Inputs/WhereParametersEmptyWhereDiag/APINotes.apinotes
new file mode 100644
index 0000000000000..5017c5737e13a
--- /dev/null
+++ b/clang/test/APINotes/Inputs/WhereParametersEmptyWhereDiag/APINotes.apinotes
@@ -0,0 +1,12 @@
+---
+Name: WhereParametersConvertDiag
+Functions:
+- Name: makeWidget
+  Where: {}
+  SwiftName: makeWidget(_:)
+Tags:
+- Name: Widget
+  Methods:
+  - Name: reset
+    Where: {}
+    SwiftName: reset()
diff --git 
a/clang/test/APINotes/Inputs/WhereParametersEmptyWhereDiag/WhereParametersConvertDiag.h
 
b/clang/test/APINotes/Inputs/WhereParametersEmptyWhereDiag/WhereParametersConvertDiag.h
new file mode 100644
index 0000000000000..6807ce279f99a
--- /dev/null
+++ 
b/clang/test/APINotes/Inputs/WhereParametersEmptyWhereDiag/WhereParametersConvertDiag.h
@@ -0,0 +1,10 @@
+#ifndef WHERE_PARAMETERS_CONVERT_DIAG_H
+#define WHERE_PARAMETERS_CONVERT_DIAG_H
+
+void makeWidget(int);
+
+struct Widget {
+  void reset();
+};
+
+#endif // WHERE_PARAMETERS_CONVERT_DIAG_H
diff --git a/clang/test/APINotes/where-parameters-convert-diags.cpp 
b/clang/test/APINotes/where-parameters-convert-diags.cpp
index ee40efeaa865b..ed0b804a5385e 100644
--- a/clang/test/APINotes/where-parameters-convert-diags.cpp
+++ b/clang/test/APINotes/where-parameters-convert-diags.cpp
@@ -1,5 +1,6 @@
-// RUN: not %clang_cc1 -fsyntax-only -fapinotes %s -I 
%S/Inputs/WhereParametersConvertDiag 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -fapinotes %s -I 
%S/Inputs/WhereParametersConvertDiag
+// RUN: not %clang_cc1 -fsyntax-only -fapinotes %s -I 
%S/Inputs/WhereParametersEmptyWhereDiag 2>&1 | FileCheck %s 
--check-prefix=EMPTY-WHERE
 
 #include "WhereParametersConvertDiag.h"
 
-// CHECK: error: 'Where' is not supported by binary API notes yet
+// EMPTY-WHERE-COUNT-2: error: 'Where' requires 'Parameters'

>From d94367712b8065500a7401a5e1c8a8f3a25babf4 Mon Sep 17 00:00:00 2001
From: stoeckoverflow <[email protected]>
Date: Fri, 19 Jun 2026 10:47:20 +0200
Subject: [PATCH 2/3] [APINotes] Clean up function selector key APIs

---
 clang/include/clang/APINotes/APINotesReader.h |  38 ++++---
 clang/include/clang/APINotes/APINotesWriter.h |  25 ++---
 clang/lib/APINotes/APINotesFormat.h           |  46 +++++++-
 clang/lib/APINotes/APINotesReader.cpp         | 105 +++++++++++++-----
 clang/lib/APINotes/APINotesWriter.cpp         |  67 ++++++-----
 clang/lib/APINotes/APINotesYAMLCompiler.cpp   |  14 ++-
 6 files changed, 205 insertions(+), 90 deletions(-)

diff --git a/clang/include/clang/APINotes/APINotesReader.h 
b/clang/include/clang/APINotes/APINotesReader.h
index c5e32dc6a51c7..8e748b5803189 100644
--- a/clang/include/clang/APINotes/APINotesReader.h
+++ b/clang/include/clang/APINotes/APINotesReader.h
@@ -161,13 +161,12 @@ class APINotesReader {
   VersionedInfo<CXXMethodInfo> lookupCXXMethod(ContextID CtxID,
                                                llvm::StringRef Name);
 
-  /// Look for information regarding the given C++ method with an optional
-  /// parameter selector. Passing std::nullopt uses the name-only key, an empty
-  /// parameter list uses an exact zero-parameter key, and a non-empty list 
uses
-  /// an exact ordered parameter key.
+  /// Look for information regarding the given C++ method with an exact
+  /// parameter selector. An empty parameter list uses an exact zero-parameter
+  /// key, and a non-empty list uses an exact ordered parameter key.
   VersionedInfo<CXXMethodInfo>
   lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
-                  std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters);
+                  llvm::ArrayRef<llvm::StringRef> Parameters);
 
   /// Look for information regarding the given global variable.
   ///
@@ -187,14 +186,13 @@ class APINotesReader {
   lookupGlobalFunction(llvm::StringRef Name,
                        std::optional<Context> Ctx = std::nullopt);
 
-  /// Look for information regarding the given global function with an optional
-  /// parameter selector. Passing std::nullopt uses the name-only key, an empty
-  /// parameter list uses an exact zero-parameter key, and a non-empty list 
uses
-  /// an exact ordered parameter key.
-  VersionedInfo<GlobalFunctionInfo> lookupGlobalFunction(
-      llvm::StringRef Name,
-      std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
-      std::optional<Context> Ctx = std::nullopt);
+  /// Look for information regarding the given global function with an exact
+  /// parameter selector. An empty parameter list uses an exact zero-parameter
+  /// key, and a non-empty list uses an exact ordered parameter key.
+  VersionedInfo<GlobalFunctionInfo>
+  lookupGlobalFunction(llvm::StringRef Name,
+                       llvm::ArrayRef<llvm::StringRef> Parameters,
+                       std::optional<Context> Ctx = std::nullopt);
 
   /// Look for information regarding the given enumerator.
   ///
@@ -240,6 +238,20 @@ class APINotesReader {
   std::optional<ContextID>
   lookupNamespaceID(llvm::StringRef Name,
                     std::optional<ContextID> ParentNamespaceID = std::nullopt);
+
+private:
+  VersionedInfo<CXXMethodInfo> lookupCXXMethodImpl(ContextID CtxID,
+                                                   llvm::StringRef Name);
+  VersionedInfo<CXXMethodInfo>
+  lookupCXXMethodImpl(ContextID CtxID, llvm::StringRef Name,
+                      llvm::ArrayRef<llvm::StringRef> Parameters);
+
+  VersionedInfo<GlobalFunctionInfo>
+  lookupGlobalFunctionImpl(llvm::StringRef Name, std::optional<Context> Ctx);
+  VersionedInfo<GlobalFunctionInfo>
+  lookupGlobalFunctionImpl(llvm::StringRef Name,
+                           llvm::ArrayRef<llvm::StringRef> Parameters,
+                           std::optional<Context> Ctx);
 };
 
 } // end namespace api_notes
diff --git a/clang/include/clang/APINotes/APINotesWriter.h 
b/clang/include/clang/APINotes/APINotesWriter.h
index 5abea950aac14..5ed6686e1bb85 100644
--- a/clang/include/clang/APINotes/APINotesWriter.h
+++ b/clang/include/clang/APINotes/APINotesWriter.h
@@ -88,12 +88,11 @@ class APINotesWriter {
   void addCXXMethod(ContextID CtxID, llvm::StringRef Name,
                     const CXXMethodInfo &Info, llvm::VersionTuple 
SwiftVersion);
 
-  /// Add information about a C++ method with an optional parameter selector.
-  /// Passing std::nullopt uses the name-only key, an empty parameter list uses
-  /// an exact zero-parameter key, and a non-empty list uses an exact ordered
-  /// parameter key.
+  /// Add information about a C++ method with an exact parameter selector. An
+  /// empty parameter list uses an exact zero-parameter key, and a non-empty
+  /// list uses an exact ordered parameter key.
   void addCXXMethod(ContextID CtxID, llvm::StringRef Name,
-                    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
+                    llvm::ArrayRef<llvm::StringRef> Parameters,
                     const CXXMethodInfo &Info, llvm::VersionTuple 
SwiftVersion);
 
   /// Add information about a specific C record field.
@@ -120,15 +119,13 @@ class APINotesWriter {
                          const GlobalFunctionInfo &Info,
                          llvm::VersionTuple SwiftVersion);
 
-  /// Add information about a global function with an optional parameter
-  /// selector. Passing std::nullopt uses the name-only key, an empty parameter
-  /// list uses an exact zero-parameter key, and a non-empty list uses an exact
-  /// ordered parameter key.
-  void
-  addGlobalFunction(std::optional<Context> Ctx, llvm::StringRef Name,
-                    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
-                    const GlobalFunctionInfo &Info,
-                    llvm::VersionTuple SwiftVersion);
+  /// Add information about a global function with an exact parameter selector.
+  /// An empty parameter list uses an exact zero-parameter key, and a non-empty
+  /// list uses an exact ordered parameter key.
+  void addGlobalFunction(std::optional<Context> Ctx, llvm::StringRef Name,
+                         llvm::ArrayRef<llvm::StringRef> Parameters,
+                         const GlobalFunctionInfo &Info,
+                         llvm::VersionTuple SwiftVersion);
 
   /// Add information about an enumerator.
   ///
diff --git a/clang/lib/APINotes/APINotesFormat.h 
b/clang/lib/APINotes/APINotesFormat.h
index 6f78ede4f608f..df67da0845baf 100644
--- a/clang/lib/APINotes/APINotesFormat.h
+++ b/clang/lib/APINotes/APINotesFormat.h
@@ -10,12 +10,12 @@
 #define LLVM_CLANG_LIB_APINOTES_APINOTESFORMAT_H
 
 #include "clang/APINotes/Types.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/PointerEmbeddedInt.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Bitcode/BitcodeConvenience.h"
 
 #include <optional>
-#include <utility>
 
 namespace clang {
 namespace api_notes {
@@ -376,9 +376,10 @@ struct FunctionTableKey {
       : parentContextID(ParentContextID), nameID(NameID) {}
 
   FunctionTableKey(uint32_t ParentContextID, uint32_t NameID,
-                   llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs)
-      : parentContextID(ParentContextID), nameID(NameID),
-        parameterTypeIDs(std::move(ParameterTypeIDs)) {}
+                   const llvm::SmallVectorImpl<IdentifierID> &ParameterTypeIDs)
+      : parentContextID(ParentContextID), nameID(NameID) {
+    parameterTypeIDs.emplace(ParameterTypeIDs.begin(), ParameterTypeIDs.end());
+  }
 
   FunctionTableKey(std::optional<Context> ParentCtx, IdentifierID NameID)
       : parentContextID(ParentCtx ? ParentCtx->id.Value
@@ -386,10 +387,12 @@ struct FunctionTableKey {
         nameID(NameID) {}
 
   FunctionTableKey(std::optional<Context> ParentCtx, IdentifierID NameID,
-                   llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs)
+                   const llvm::SmallVectorImpl<IdentifierID> &ParameterTypeIDs)
       : parentContextID(ParentCtx ? ParentCtx->id.Value
                                   : static_cast<uint32_t>(-1)),
-        nameID(NameID), parameterTypeIDs(std::move(ParameterTypeIDs)) {}
+        nameID(NameID) {
+    parameterTypeIDs.emplace(ParameterTypeIDs.begin(), ParameterTypeIDs.end());
+  }
 
   llvm::hash_code hashValue() const {
     auto Hash = llvm::hash_combine(parentContextID, nameID,
@@ -403,6 +406,37 @@ struct FunctionTableKey {
   }
 };
 
+template <typename GetIdentifierFn>
+std::optional<FunctionTableKey>
+getFunctionKeyImpl(uint32_t ParentContextID, llvm::StringRef Name,
+                   GetIdentifierFn GetIdentifier) {
+  std::optional<IdentifierID> NameID = GetIdentifier(Name);
+  if (!NameID)
+    return std::nullopt;
+
+  return FunctionTableKey(ParentContextID, *NameID);
+}
+
+template <typename GetIdentifierFn>
+std::optional<FunctionTableKey>
+getFunctionKeyImpl(uint32_t ParentContextID, llvm::StringRef Name,
+                   llvm::ArrayRef<llvm::StringRef> Parameters,
+                   GetIdentifierFn GetIdentifier) {
+  std::optional<IdentifierID> NameID = GetIdentifier(Name);
+  if (!NameID)
+    return std::nullopt;
+
+  llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs;
+  ParameterTypeIDs.reserve(Parameters.size());
+  for (llvm::StringRef Parameter : Parameters) {
+    std::optional<IdentifierID> ParameterID = GetIdentifier(Parameter);
+    if (!ParameterID)
+      return std::nullopt;
+    ParameterTypeIDs.push_back(*ParameterID);
+  }
+  return FunctionTableKey(ParentContextID, *NameID, ParameterTypeIDs);
+}
+
 inline bool operator==(const FunctionTableKey &lhs,
                        const FunctionTableKey &rhs) {
   return lhs.parentContextID == rhs.parentContextID &&
diff --git a/clang/lib/APINotes/APINotesReader.cpp 
b/clang/lib/APINotes/APINotesReader.cpp
index 5ac172b369444..9305a5f10b4e8 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -71,7 +71,7 @@ static FunctionTableKey readFunctionTableKey(const uint8_t 
*Data,
   assert((FunctionKeyFlags & ~FunctionKeyHasParameterSelector) == 0 &&
          "Unexpected function table key flags");
   if (FunctionKeyFlags & FunctionKeyHasParameterSelector)
-    return {CtxID, NameID, std::move(ParameterTypeIDs)};
+    return {CtxID, NameID, ParameterTypeIDs};
 
   assert(ParameterTypeIDs.empty() &&
          "Broad function table key should not store parameters");
@@ -855,12 +855,16 @@ class APINotesReader::Implementation {
                                     llvm::SmallVectorImpl<uint64_t> &Scratch);
   llvm::Error readGlobalVariableBlock(llvm::BitstreamCursor &Cursor,
                                       llvm::SmallVectorImpl<uint64_t> 
&Scratch);
+  std::optional<FunctionTableKey> getFunctionKey(uint32_t ParentContextID,
+                                                 llvm::StringRef Name);
   std::optional<FunctionTableKey>
   getFunctionKey(uint32_t ParentContextID, llvm::StringRef Name,
-                 std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters);
+                 llvm::ArrayRef<llvm::StringRef> Parameters);
+  std::optional<FunctionTableKey>
+  getFunctionKey(std::optional<Context> ParentContext, llvm::StringRef Name);
   std::optional<FunctionTableKey>
   getFunctionKey(std::optional<Context> ParentContext, llvm::StringRef Name,
-                 std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters);
+                 llvm::ArrayRef<llvm::StringRef> Parameters);
 
   llvm::Error readGlobalFunctionBlock(llvm::BitstreamCursor &Cursor,
                                       llvm::SmallVectorImpl<uint64_t> 
&Scratch);
@@ -887,31 +891,32 @@ 
APINotesReader::Implementation::getIdentifier(llvm::StringRef Str) {
   return *Known;
 }
 
+std::optional<FunctionTableKey>
+APINotesReader::Implementation::getFunctionKey(uint32_t ParentContextID,
+                                               llvm::StringRef Name) {
+  return getFunctionKeyImpl(ParentContextID, Name, [this](llvm::StringRef S) {
+    return getIdentifier(S);
+  });
+}
+
 std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
     uint32_t ParentContextID, llvm::StringRef Name,
-    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters) {
-  std::optional<IdentifierID> NameID = getIdentifier(Name);
-  if (!NameID)
-    return std::nullopt;
-
-  if (!Parameters)
-    return FunctionTableKey(ParentContextID, *NameID);
+    llvm::ArrayRef<llvm::StringRef> Parameters) {
+  return getFunctionKeyImpl(
+      ParentContextID, Name, Parameters,
+      [this](llvm::StringRef S) { return getIdentifier(S); });
+}
 
-  llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs;
-  ParameterTypeIDs.reserve(Parameters->size());
-  for (llvm::StringRef Parameter : *Parameters) {
-    std::optional<IdentifierID> ParameterID = getIdentifier(Parameter);
-    if (!ParameterID)
-      return std::nullopt;
-    ParameterTypeIDs.push_back(*ParameterID);
-  }
-  return FunctionTableKey(ParentContextID, *NameID,
-                          std::move(ParameterTypeIDs));
+std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
+    std::optional<Context> ParentContext, llvm::StringRef Name) {
+  uint32_t ParentContextID =
+      ParentContext ? ParentContext->id.Value : static_cast<uint32_t>(-1);
+  return getFunctionKey(ParentContextID, Name);
 }
 
 std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
     std::optional<Context> ParentContext, llvm::StringRef Name,
-    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters) {
+    llvm::ArrayRef<llvm::StringRef> Parameters) {
   uint32_t ParentContextID =
       ParentContext ? ParentContext->id.Value : static_cast<uint32_t>(-1);
   return getFunctionKey(ParentContextID, Name, Parameters);
@@ -2333,12 +2338,35 @@ auto APINotesReader::lookupField(ContextID CtxID, 
llvm::StringRef Name)
 
 auto APINotesReader::lookupCXXMethod(ContextID CtxID, llvm::StringRef Name)
     -> VersionedInfo<CXXMethodInfo> {
-  return lookupCXXMethod(CtxID, Name, std::nullopt);
+  return lookupCXXMethodImpl(CtxID, Name);
 }
 
-auto APINotesReader::lookupCXXMethod(
+auto APINotesReader::lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
+                                     llvm::ArrayRef<llvm::StringRef> 
Parameters)
+    -> VersionedInfo<CXXMethodInfo> {
+  return lookupCXXMethodImpl(CtxID, Name, Parameters);
+}
+
+auto APINotesReader::lookupCXXMethodImpl(ContextID CtxID, llvm::StringRef Name)
+    -> VersionedInfo<CXXMethodInfo> {
+  if (!Implementation->CXXMethodTable)
+    return std::nullopt;
+
+  std::optional<FunctionTableKey> Key =
+      Implementation->getFunctionKey(CtxID.Value, Name);
+  if (!Key)
+    return std::nullopt;
+
+  auto Known = Implementation->CXXMethodTable->find(*Key);
+  if (Known == Implementation->CXXMethodTable->end())
+    return std::nullopt;
+
+  return {Implementation->SwiftVersion, *Known};
+}
+
+auto APINotesReader::lookupCXXMethodImpl(
     ContextID CtxID, llvm::StringRef Name,
-    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters)
+    llvm::ArrayRef<llvm::StringRef> Parameters)
     -> VersionedInfo<CXXMethodInfo> {
   if (!Implementation->CXXMethodTable)
     return std::nullopt;
@@ -2377,12 +2405,35 @@ auto 
APINotesReader::lookupGlobalVariable(llvm::StringRef Name,
 auto APINotesReader::lookupGlobalFunction(llvm::StringRef Name,
                                           std::optional<Context> Ctx)
     -> VersionedInfo<GlobalFunctionInfo> {
-  return lookupGlobalFunction(Name, std::nullopt, Ctx);
+  return lookupGlobalFunctionImpl(Name, Ctx);
 }
 
 auto APINotesReader::lookupGlobalFunction(
-    llvm::StringRef Name,
-    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
+    llvm::StringRef Name, llvm::ArrayRef<llvm::StringRef> Parameters,
+    std::optional<Context> Ctx) -> VersionedInfo<GlobalFunctionInfo> {
+  return lookupGlobalFunctionImpl(Name, Parameters, Ctx);
+}
+
+auto APINotesReader::lookupGlobalFunctionImpl(llvm::StringRef Name,
+                                              std::optional<Context> Ctx)
+    -> VersionedInfo<GlobalFunctionInfo> {
+  if (!Implementation->GlobalFunctionTable)
+    return std::nullopt;
+
+  std::optional<FunctionTableKey> Key =
+      Implementation->getFunctionKey(Ctx, Name);
+  if (!Key)
+    return std::nullopt;
+
+  auto Known = Implementation->GlobalFunctionTable->find(*Key);
+  if (Known == Implementation->GlobalFunctionTable->end())
+    return std::nullopt;
+
+  return {Implementation->SwiftVersion, *Known};
+}
+
+auto APINotesReader::lookupGlobalFunctionImpl(
+    llvm::StringRef Name, llvm::ArrayRef<llvm::StringRef> Parameters,
     std::optional<Context> Ctx) -> VersionedInfo<GlobalFunctionInfo> {
   if (!Implementation->GlobalFunctionTable)
     return std::nullopt;
diff --git a/clang/lib/APINotes/APINotesWriter.cpp 
b/clang/lib/APINotes/APINotesWriter.cpp
index 48abeced839fc..0aa9812693386 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -137,24 +137,37 @@ class APINotesWriter::Implementation {
         .first->second;
   }
 
-  FunctionTableKey
-  getFunctionKey(uint32_t ParentContextID, StringRef Name,
-                 std::optional<ArrayRef<StringRef>> Parameters = std::nullopt) 
{
-    IdentifierID NameID = getIdentifier(Name);
-    if (!Parameters)
-      return FunctionTableKey(ParentContextID, NameID);
-
-    llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs;
-    ParameterTypeIDs.reserve(Parameters->size());
-    for (StringRef Parameter : *Parameters)
-      ParameterTypeIDs.push_back(getIdentifier(Parameter));
-    return FunctionTableKey(ParentContextID, NameID,
-                            std::move(ParameterTypeIDs));
-  }
-
-  FunctionTableKey
-  getFunctionKey(std::optional<Context> ParentContext, StringRef Name,
-                 std::optional<ArrayRef<StringRef>> Parameters = std::nullopt) 
{
+  FunctionTableKey getFunctionKey(uint32_t ParentContextID, StringRef Name) {
+    std::optional<FunctionTableKey> Key =
+        getFunctionKeyImpl(ParentContextID, Name,
+                           [this](StringRef S) -> std::optional<IdentifierID> {
+                             return getIdentifier(S);
+                           });
+    assert(Key && "Writer identifier lookup should not fail");
+    return *Key;
+  }
+
+  FunctionTableKey getFunctionKey(uint32_t ParentContextID, StringRef Name,
+                                  ArrayRef<StringRef> Parameters) {
+    std::optional<FunctionTableKey> Key =
+        getFunctionKeyImpl(ParentContextID, Name, Parameters,
+                           [this](StringRef S) -> std::optional<IdentifierID> {
+                             return getIdentifier(S);
+                           });
+    assert(Key && "Writer identifier lookup should not fail");
+    return *Key;
+  }
+
+  FunctionTableKey getFunctionKey(std::optional<Context> ParentContext,
+                                  StringRef Name) {
+    uint32_t ParentContextID =
+        ParentContext ? ParentContext->id.Value : static_cast<uint32_t>(-1);
+    return getFunctionKey(ParentContextID, Name);
+  }
+
+  FunctionTableKey getFunctionKey(std::optional<Context> ParentContext,
+                                  StringRef Name,
+                                  ArrayRef<StringRef> Parameters) {
     uint32_t ParentContextID =
         ParentContext ? ParentContext->id.Value : static_cast<uint32_t>(-1);
     return getFunctionKey(ParentContextID, Name, Parameters);
@@ -1607,13 +1620,14 @@ void APINotesWriter::addObjCMethod(ContextID CtxID, 
ObjCSelectorRef Selector,
 void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,
                                   const CXXMethodInfo &Info,
                                   VersionTuple SwiftVersion) {
-  addCXXMethod(CtxID, Name, std::nullopt, Info, SwiftVersion);
+  FunctionTableKey Key = Implementation->getFunctionKey(CtxID.Value, Name);
+  Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
 }
 
-void APINotesWriter::addCXXMethod(
-    ContextID CtxID, llvm::StringRef Name,
-    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
-    const CXXMethodInfo &Info, VersionTuple SwiftVersion) {
+void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,
+                                  llvm::ArrayRef<llvm::StringRef> Parameters,
+                                  const CXXMethodInfo &Info,
+                                  VersionTuple SwiftVersion) {
   FunctionTableKey Key =
       Implementation->getFunctionKey(CtxID.Value, Name, Parameters);
   Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
@@ -1640,13 +1654,14 @@ void 
APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
                                        llvm::StringRef Name,
                                        const GlobalFunctionInfo &Info,
                                        VersionTuple SwiftVersion) {
-  addGlobalFunction(Ctx, Name, std::nullopt, Info, SwiftVersion);
+  FunctionTableKey Key = Implementation->getFunctionKey(Ctx, Name);
+  Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
 }
 
 void APINotesWriter::addGlobalFunction(
     std::optional<Context> Ctx, llvm::StringRef Name,
-    std::optional<llvm::ArrayRef<llvm::StringRef>> Parameters,
-    const GlobalFunctionInfo &Info, VersionTuple SwiftVersion) {
+    llvm::ArrayRef<llvm::StringRef> Parameters, const GlobalFunctionInfo &Info,
+    VersionTuple SwiftVersion) {
   FunctionTableKey Key = Implementation->getFunctionKey(Ctx, Name, Parameters);
   Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
 }
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp 
b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index d02cd3a3f3c56..8e947711dec2f 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -1173,8 +1173,11 @@ class YAMLConverter {
 
       CXXMethodInfo MI;
       convertFunction(CXXMethod, MI);
-      Writer.addCXXMethod(TagCtxID, CXXMethod.Name, WhereParameters, MI,
-                          SwiftVersion);
+      if (WhereParameters)
+        Writer.addCXXMethod(TagCtxID, CXXMethod.Name, *WhereParameters, MI,
+                            SwiftVersion);
+      else
+        Writer.addCXXMethod(TagCtxID, CXXMethod.Name, MI, SwiftVersion);
     }
 
     // Convert nested tags.
@@ -1260,8 +1263,11 @@ class YAMLConverter {
 
       GlobalFunctionInfo GFI;
       convertFunction(Function, GFI);
-      Writer.addGlobalFunction(Ctx, Function.Name, WhereParameters, GFI,
-                               SwiftVersion);
+      if (WhereParameters)
+        Writer.addGlobalFunction(Ctx, Function.Name, *WhereParameters, GFI,
+                                 SwiftVersion);
+      else
+        Writer.addGlobalFunction(Ctx, Function.Name, GFI, SwiftVersion);
     }
 
     // Write all enumerators.

>From ca9bc2b80e6beb3bf41d3f9914a4e41defaceb2b Mon Sep 17 00:00:00 2001
From: stoeckoverflow <[email protected]>
Date: Fri, 19 Jun 2026 11:17:22 +0200
Subject: [PATCH 3/3] [APINotes] Apply Where.Parameters selectors in Sema

---
 clang/lib/Sema/SemaAPINotes.cpp               |  45 +++++++
 .../Headers/WhereParametersSema.apinotes      | 126 ++++++++++++++++++
 .../Inputs/Headers/WhereParametersSema.h      |  51 +++++++
 .../APINotes/Inputs/Headers/module.modulemap  |   5 +
 clang/test/APINotes/where-parameters-sema.cpp | 110 +++++++++++++++
 5 files changed, 337 insertions(+)
 create mode 100644 
clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
 create mode 100644 clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
 create mode 100644 clang/test/APINotes/where-parameters-sema.cpp

diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index a99408a4c8a7b..c2657d31a4219 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -993,6 +993,29 @@ UnwindTagContext(TagDecl *DC, api_notes::APINotesManager 
&APINotes) {
   return std::nullopt;
 }
 
+static std::optional<SmallVector<std::string, 4>>
+getAPINotesParameterSelector(const Sema &S, const FunctionDecl *FD) {
+  const auto *FPT = FD->getType()->getAs<FunctionProtoType>();
+  if (!FPT)
+    return std::nullopt;
+
+  SmallVector<std::string, 4> Parameters;
+  Parameters.reserve(FPT->getNumParams());
+  for (QualType ParamType : FPT->param_types())
+    Parameters.push_back(ParamType.getUnqualifiedType().getAsString(
+        S.Context.getPrintingPolicy()));
+  return Parameters;
+}
+
+static SmallVector<StringRef, 4>
+getAPINotesParameterSelectorRefs(ArrayRef<std::string> Strings) {
+  SmallVector<StringRef, 4> Refs;
+  Refs.reserve(Strings.size());
+  for (const std::string &String : Strings)
+    Refs.push_back(String);
+  return Refs;
+}
+
 /// Process API notes that are associated with this declaration, mapping them
 /// to attributes as appropriate.
 void Sema::ProcessAPINotes(Decl *D) {
@@ -1022,10 +1045,21 @@ void Sema::ProcessAPINotes(Decl *D) {
     // Global functions.
     if (auto FD = dyn_cast<FunctionDecl>(D)) {
       if (FD->getDeclName().isIdentifier()) {
+        std::optional<SmallVector<std::string, 4>> ParameterStrings =
+            getAPINotesParameterSelector(*this, FD);
+        SmallVector<StringRef, 4> Parameters;
+        if (ParameterStrings)
+          Parameters = getAPINotesParameterSelectorRefs(*ParameterStrings);
         for (auto Reader : Readers) {
           auto Info =
               Reader->lookupGlobalFunction(FD->getName(), APINotesContext);
           ProcessVersionedAPINotes(*this, FD, Info);
+
+          if (ParameterStrings) {
+            Info = Reader->lookupGlobalFunction(FD->getName(), Parameters,
+                                                APINotesContext);
+            ProcessVersionedAPINotes(*this, FD, Info);
+          }
         }
       }
 
@@ -1209,6 +1243,11 @@ void Sema::ProcessAPINotes(Decl *D) {
       if (!isa<CXXConstructorDecl>(CXXMethod) &&
           !isa<CXXDestructorDecl>(CXXMethod) &&
           !isa<CXXConversionDecl>(CXXMethod)) {
+        std::optional<SmallVector<std::string, 4>> ParameterStrings =
+            getAPINotesParameterSelector(*this, CXXMethod);
+        SmallVector<StringRef, 4> Parameters;
+        if (ParameterStrings)
+          Parameters = getAPINotesParameterSelectorRefs(*ParameterStrings);
         for (auto Reader : Readers) {
           if (auto Context = UnwindTagContext(TagContext, APINotes)) {
             std::string MethodName;
@@ -1221,6 +1260,12 @@ void Sema::ProcessAPINotes(Decl *D) {
 
             auto Info = Reader->lookupCXXMethod(Context->id, MethodName);
             ProcessVersionedAPINotes(*this, CXXMethod, Info);
+
+            if (ParameterStrings) {
+              Info =
+                  Reader->lookupCXXMethod(Context->id, MethodName, Parameters);
+              ProcessVersionedAPINotes(*this, CXXMethod, Info);
+            }
           }
         }
       }
diff --git a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes 
b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
new file mode 100644
index 0000000000000..2a9f9c921347b
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
@@ -0,0 +1,126 @@
+---
+Name: WhereParametersSema
+Functions:
+- Name: makeWidget
+  Where:
+    Parameters:
+    - int
+  SwiftName: makeIntWidget(_:)
+- Name: makeWidget
+  Where:
+    Parameters:
+    - double
+  SwiftName: makeDoubleWidget(_:)
+- Name: makeWidget
+  Where:
+    Parameters: []
+  SwiftName: makeCurrentWidget()
+- Name: broadGlobal
+  SwiftPrivate: true
+- Name: coexistGlobal
+  SwiftPrivate: true
+- Name: coexistGlobal
+  Where:
+    Parameters:
+    - int
+  SwiftName: coexistGlobalInt(_:)
+- Name: mismatchGlobal
+  Where:
+    Parameters:
+    - int
+  SwiftName: shouldNotApplyGlobal(_:)
+- Name: aliasGlobal
+  Where:
+    Parameters:
+    - int
+  SwiftName: shouldNotApplyAliasGlobal(_:)
+- Name: rawIntGlobal
+  Where:
+    Parameters:
+    - int
+  SwiftName: rawIntGlobal(_:)
+- Name: constValueGlobal
+  Where:
+    Parameters:
+    - int
+  SwiftName: constValueGlobal(_:)
+Namespaces:
+- Name: SelectorNamespace
+  Functions:
+  - Name: makeNamespaced
+    Where:
+      Parameters:
+      - int
+    SwiftName: makeNamespacedInt(_:)
+  - Name: makeNamespaced
+    Where:
+      Parameters:
+      - double
+    SwiftName: makeNamespacedDouble(_:)
+Tags:
+- Name: SelectorWidget
+  Methods:
+  - Name: setValue
+    Where:
+      Parameters:
+      - int
+    SwiftName: setIntValue(_:)
+  - Name: setValue
+    Where:
+      Parameters:
+      - double
+    SwiftName: setDoubleValue(_:)
+  - Name: setValue
+    Where:
+      Parameters: []
+    SwiftName: currentValue()
+  - Name: broad
+    SwiftPrivate: true
+  - Name: coexist
+    SwiftPrivate: true
+  - Name: coexist
+    Where:
+      Parameters:
+      - int
+    SwiftName: coexistInt(_:)
+  - Name: defaults
+    Where:
+      Parameters:
+      - int
+      - double
+    SwiftName: defaultsWithTwoParameters(_:_:)
+  - Name: configure
+    Where:
+      Parameters:
+      - int
+    SwiftName: configureInt(_:)
+  - Name: mismatch
+    Where:
+      Parameters:
+      - int
+    SwiftName: shouldNotApplyMethod(_:)
+  - Name: alias
+    Where:
+      Parameters:
+      - int
+    SwiftName: shouldNotApplyAliasMethod(_:)
+  - Name: rawInt
+    Where:
+      Parameters:
+      - int
+    SwiftName: rawInt(_:)
+  - Name: constValue
+    Where:
+      Parameters:
+      - int
+    SwiftName: constValue(_:)
+  - Name: operator+
+    Where:
+      Parameters:
+      - int
+    SwiftName: plusInt(_:)
+  - Name: operator+
+    Where:
+      Parameters:
+      - double
+    SwiftName: plusDouble(_:)
diff --git a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h 
b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
new file mode 100644
index 0000000000000..1cd10676e5533
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
@@ -0,0 +1,51 @@
+#ifndef WHERE_PARAMETERS_SEMA_H
+#define WHERE_PARAMETERS_SEMA_H
+
+using AliasInt = int;
+
+void makeWidget(int);
+void makeWidget(double);
+void makeWidget();
+
+void broadGlobal(int);
+void broadGlobal(double);
+
+void coexistGlobal(int);
+void coexistGlobal(double);
+
+void mismatchGlobal(float);
+void aliasGlobal(AliasInt);
+void rawIntGlobal(int);
+void constValueGlobal(const int);
+
+namespace SelectorNamespace {
+void makeNamespaced(int);
+void makeNamespaced(double);
+}
+
+struct SelectorWidget {
+  void setValue(int);
+  void setValue(double);
+  void setValue();
+
+  void broad(int);
+  void broad(double);
+
+  void coexist(int);
+  void coexist(double);
+
+  void defaults(int, double = 0);
+  void defaults(int);
+
+  static void configure(int);
+
+  void mismatch(float);
+  void alias(AliasInt);
+  void rawInt(int);
+  void constValue(const int);
+
+  SelectorWidget operator+(int);
+  SelectorWidget operator+(double);
+};
+
+#endif // WHERE_PARAMETERS_SEMA_H
diff --git a/clang/test/APINotes/Inputs/Headers/module.modulemap 
b/clang/test/APINotes/Inputs/Headers/module.modulemap
index 7bcf33644a14f..592d482ea7a57 100644
--- a/clang/test/APINotes/Inputs/Headers/module.modulemap
+++ b/clang/test/APINotes/Inputs/Headers/module.modulemap
@@ -70,3 +70,8 @@ module UnsafeBufferUsage {
   header "UnsafeBufferUsage.h"
   export *
 }
+
+module WhereParametersSema {
+  header "WhereParametersSema.h"
+  export *
+}
diff --git a/clang/test/APINotes/where-parameters-sema.cpp 
b/clang/test/APINotes/where-parameters-sema.cpp
new file mode 100644
index 0000000000000..7d1dcf7b61abb
--- /dev/null
+++ b/clang/test/APINotes/where-parameters-sema.cpp
@@ -0,0 +1,110 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
makeWidget -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-OVERLOADS %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
broadGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-BROAD %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
coexistGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-COEXIST %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
mismatchGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-MISMATCH %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
aliasGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-ALIAS %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
rawIntGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-RAW-INT %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
constValueGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-CONST %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorNamespace::makeNamespaced -x c++ | FileCheck 
--check-prefix=CHECK-GLOBAL-NAMESPACE %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::setValue -x c++ | FileCheck 
--check-prefix=CHECK-METHOD-OVERLOADS %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::broad -x c++ | FileCheck --check-prefix=CHECK-METHOD-BROAD %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::coexist -x c++ | FileCheck --check-prefix=CHECK-METHOD-COEXIST 
%s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::defaults -x c++ | FileCheck 
--check-prefix=CHECK-METHOD-DEFAULTS %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::configure -x c++ | FileCheck --check-prefix=CHECK-METHOD-STATIC 
%s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::mismatch -x c++ | FileCheck 
--check-prefix=CHECK-METHOD-MISMATCH %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::alias -x c++ | FileCheck --check-prefix=CHECK-METHOD-ALIAS %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::rawInt -x c++ | FileCheck --check-prefix=CHECK-METHOD-RAW-INT %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::constValue -x c++ | FileCheck --check-prefix=CHECK-METHOD-CONST 
%s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::operator+ -x c++ | FileCheck 
--check-prefix=CHECK-METHOD-OPERATOR %s
+
+#include "WhereParametersSema.h"
+
+// CHECK-GLOBAL-OVERLOADS: FunctionDecl {{.+}} makeWidget 'void (int)'
+// CHECK-GLOBAL-OVERLOADS-NEXT: ParmVarDecl {{.+}} 'int'
+// CHECK-GLOBAL-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "makeIntWidget(_:)"
+// CHECK-GLOBAL-OVERLOADS: FunctionDecl {{.+}} makeWidget 'void (double)'
+// CHECK-GLOBAL-OVERLOADS-NEXT: ParmVarDecl {{.+}} 'double'
+// CHECK-GLOBAL-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "makeDoubleWidget(_:)"
+// CHECK-GLOBAL-OVERLOADS: FunctionDecl {{.+}} makeWidget 'void ()'
+// CHECK-GLOBAL-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "makeCurrentWidget()"
+
+// CHECK-GLOBAL-BROAD: FunctionDecl {{.+}} broadGlobal 'void (int)'
+// CHECK-GLOBAL-BROAD: SwiftPrivateAttr
+// CHECK-GLOBAL-BROAD: FunctionDecl {{.+}} broadGlobal 'void (double)'
+// CHECK-GLOBAL-BROAD: SwiftPrivateAttr
+
+// CHECK-GLOBAL-COEXIST: FunctionDecl {{.+}} coexistGlobal 'void (int)'
+// CHECK-GLOBAL-COEXIST: SwiftPrivateAttr
+// CHECK-GLOBAL-COEXIST: SwiftNameAttr {{.+}} "coexistGlobalInt(_:)"
+// CHECK-GLOBAL-COEXIST: FunctionDecl {{.+}} coexistGlobal 'void (double)'
+// CHECK-GLOBAL-COEXIST: SwiftPrivateAttr
+// CHECK-GLOBAL-COEXIST-NOT: SwiftNameAttr
+
+// CHECK-GLOBAL-MISMATCH: FunctionDecl {{.+}} mismatchGlobal 'void (float)'
+// CHECK-GLOBAL-MISMATCH-NOT: SwiftNameAttr
+
+// CHECK-GLOBAL-ALIAS: FunctionDecl {{.+}} aliasGlobal 'void (AliasInt)'
+// CHECK-GLOBAL-ALIAS-NOT: SwiftNameAttr
+
+// CHECK-GLOBAL-RAW-INT: FunctionDecl {{.+}} rawIntGlobal 'void (int)'
+// CHECK-GLOBAL-RAW-INT: SwiftNameAttr {{.+}} "rawIntGlobal(_:)"
+
+// CHECK-GLOBAL-CONST: FunctionDecl {{.+}} constValueGlobal 'void (const int)'
+// CHECK-GLOBAL-CONST: SwiftNameAttr {{.+}} "constValueGlobal(_:)"
+
+// CHECK-GLOBAL-NAMESPACE: FunctionDecl {{.+}} makeNamespaced 'void (int)'
+// CHECK-GLOBAL-NAMESPACE-NEXT: ParmVarDecl {{.+}} 'int'
+// CHECK-GLOBAL-NAMESPACE-NEXT: SwiftNameAttr {{.+}} "makeNamespacedInt(_:)"
+// CHECK-GLOBAL-NAMESPACE: FunctionDecl {{.+}} makeNamespaced 'void (double)'
+// CHECK-GLOBAL-NAMESPACE-NEXT: ParmVarDecl {{.+}} 'double'
+// CHECK-GLOBAL-NAMESPACE-NEXT: SwiftNameAttr {{.+}} "makeNamespacedDouble(_:)"
+
+// CHECK-METHOD-OVERLOADS: CXXMethodDecl {{.+}} setValue 'void (int)'
+// CHECK-METHOD-OVERLOADS-NEXT: ParmVarDecl {{.+}} 'int'
+// CHECK-METHOD-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "setIntValue(_:)"
+// CHECK-METHOD-OVERLOADS: CXXMethodDecl {{.+}} setValue 'void (double)'
+// CHECK-METHOD-OVERLOADS-NEXT: ParmVarDecl {{.+}} 'double'
+// CHECK-METHOD-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "setDoubleValue(_:)"
+// CHECK-METHOD-OVERLOADS: CXXMethodDecl {{.+}} setValue 'void ()'
+// CHECK-METHOD-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "currentValue()"
+
+// CHECK-METHOD-BROAD: CXXMethodDecl {{.+}} broad 'void (int)'
+// CHECK-METHOD-BROAD: SwiftPrivateAttr
+// CHECK-METHOD-BROAD: CXXMethodDecl {{.+}} broad 'void (double)'
+// CHECK-METHOD-BROAD: SwiftPrivateAttr
+
+// CHECK-METHOD-COEXIST: CXXMethodDecl {{.+}} coexist 'void (int)'
+// CHECK-METHOD-COEXIST: SwiftPrivateAttr
+// CHECK-METHOD-COEXIST: SwiftNameAttr {{.+}} "coexistInt(_:)"
+// CHECK-METHOD-COEXIST: CXXMethodDecl {{.+}} coexist 'void (double)'
+// CHECK-METHOD-COEXIST: SwiftPrivateAttr
+// CHECK-METHOD-COEXIST-NOT: SwiftNameAttr
+
+// CHECK-METHOD-DEFAULTS: CXXMethodDecl {{.+}} defaults 'void (int, double)'
+// CHECK-METHOD-DEFAULTS: SwiftNameAttr {{.+}} 
"defaultsWithTwoParameters(_:_:)"
+// CHECK-METHOD-DEFAULTS: CXXMethodDecl {{.+}} defaults 'void (int)'
+// CHECK-METHOD-DEFAULTS-NOT: SwiftNameAttr
+
+// CHECK-METHOD-STATIC: CXXMethodDecl {{.+}} configure 'void (int)' static
+// CHECK-METHOD-STATIC: SwiftNameAttr {{.+}} "configureInt(_:)"
+
+// CHECK-METHOD-MISMATCH: CXXMethodDecl {{.+}} mismatch 'void (float)'
+// CHECK-METHOD-MISMATCH-NOT: SwiftNameAttr
+
+// CHECK-METHOD-ALIAS: CXXMethodDecl {{.+}} alias 'void (AliasInt)'
+// CHECK-METHOD-ALIAS-NOT: SwiftNameAttr
+
+// CHECK-METHOD-RAW-INT: CXXMethodDecl {{.+}} rawInt 'void (int)'
+// CHECK-METHOD-RAW-INT: SwiftNameAttr {{.+}} "rawInt(_:)"
+
+// CHECK-METHOD-CONST: CXXMethodDecl {{.+}} constValue 'void (const int)'
+// CHECK-METHOD-CONST: SwiftNameAttr {{.+}} "constValue(_:)"
+
+// CHECK-METHOD-OPERATOR: CXXMethodDecl {{.+}} operator+ 'SelectorWidget (int)'
+// CHECK-METHOD-OPERATOR-NEXT: ParmVarDecl {{.+}} 'int'
+// CHECK-METHOD-OPERATOR-NEXT: SwiftNameAttr {{.+}} "plusInt(_:)"
+// CHECK-METHOD-OPERATOR: CXXMethodDecl {{.+}} operator+ 'SelectorWidget 
(double)'
+// CHECK-METHOD-OPERATOR-NEXT: ParmVarDecl {{.+}} 'double'
+// CHECK-METHOD-OPERATOR-NEXT: SwiftNameAttr {{.+}} "plusDouble(_:)"

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to