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

This PR adds `Where.Object` selectors for C++ method API notes. They let API 
notes distinguish overloads by the implicit object parameter qualifiers, such 
as `const`, `volatile`, `&`, and `&&`. Static methods are unchanged because 
they have no implicit object parameter.

```cpp
struct Builder {
  Result build() &;
  Result build() &&;
  Result build() const &;
};
```

To distinguish these declarations, the selector model includes an `Object` 
constraint:

```yaml
Tags:
- Name: Builder
  Methods:
  - Name: build
    Where:
      Parameters: []
      Object:
        Ref: lvalue
    SwiftName: buildFromLValue()
  - Name: build
    Where:
      Parameters: []
      Object:
        Ref: rvalue
    SwiftName: buildFromRValue()
  - Name: build
    Where:
      Parameters: []
      Object:
        Const: true
        Ref: lvalue
    SwiftName: buildFromConstLValue()
```

Changes:
- Adds `Where.Object` YAML support for C++ methods.
- Adds a shared object-selector representation with `Const`, `Volatile`, and 
`Ref`.
- Extends C++ method lookup/writer keys to include object selectors.
- Applies less-constrained object selectors before more-constrained selectors 
so specific notes can refine broader ones.
- Extends unmatched-selector diagnostics to track object-only and 
parameter-plus-object selectors.
- Keeps global functions and static C++ methods unchanged.

Tests:
- Matching `const`, `volatile`, lvalue-ref, and rvalue-ref qualified C++ 
methods.
- Combined object qualifiers such as `const volatile &`, `const &&`, and 
`volatile &&`.
- Coexistence of broad method notes with object-qualified notes.
- Object selector diagnostics for malformed, duplicate, and unmatched entries.
- Static methods remain unaffected because they have no implicit object 
parameter.

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


>From 42b6514b148da69dbd814eeeba9cb8e1742063fb Mon Sep 17 00:00:00 2001
From: stoeckoverflow <[email protected]>
Date: Tue, 11 Aug 2026 11:54:31 +0200
Subject: [PATCH] [APINotes] Add Where.Object selectors for C++ methods

---
 clang/include/clang/APINotes/APINotesReader.h |  20 ++-
 clang/include/clang/APINotes/APINotesWriter.h |   6 +
 clang/include/clang/APINotes/Types.h          | 150 ++++++++++++++++--
 clang/lib/APINotes/APINotesFormat.h           |  62 +++++++-
 clang/lib/APINotes/APINotesReader.cpp         | 122 +++++++++++---
 clang/lib/APINotes/APINotesWriter.cpp         |  77 ++++++++-
 clang/lib/APINotes/APINotesYAMLCompiler.cpp   | 132 ++++++++++-----
 clang/lib/Sema/SemaAPINotes.cpp               | 141 +++++++++++++---
 clang/lib/Sema/SemaAPINotesInternal.h         |   8 +-
 .../Headers/WhereObjectQualifiers.apinotes    |  96 +++++++++++
 .../Inputs/Headers/WhereObjectQualifiers.h    |  30 ++++
 .../APINotes/Inputs/Headers/module.modulemap  |   5 +
 .../APINotes.apinotes                         |  46 ++++++
 .../WhereObjectQualifiers.h                   |  14 ++
 .../test/APINotes/where-object-qualifiers.cpp |  63 ++++++++
 15 files changed, 865 insertions(+), 107 deletions(-)
 create mode 100644 
clang/test/APINotes/Inputs/Headers/WhereObjectQualifiers.apinotes
 create mode 100644 clang/test/APINotes/Inputs/Headers/WhereObjectQualifiers.h
 create mode 100644 
clang/test/APINotes/Inputs/WhereObjectQualifiersDiag/APINotes.apinotes
 create mode 100644 
clang/test/APINotes/Inputs/WhereObjectQualifiersDiag/WhereObjectQualifiers.h
 create mode 100644 clang/test/APINotes/where-object-qualifiers.cpp

diff --git a/clang/include/clang/APINotes/APINotesReader.h 
b/clang/include/clang/APINotes/APINotesReader.h
index d74232bc334c6..99303c8a8ba02 100644
--- a/clang/include/clang/APINotes/APINotesReader.h
+++ b/clang/include/clang/APINotes/APINotesReader.h
@@ -170,6 +170,12 @@ class APINotesReader {
   lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
                   llvm::ArrayRef<std::string> Parameters);
 
+  /// Look for information regarding the given C++ method with a composed
+  /// selector. Omitted selector components use the broad name-based key.
+  VersionedInfo<CXXMethodInfo>
+  lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
+                  const FunctionSelector &Selector);
+
   /// Build the selector key for the given C++ method.
   std::optional<APINotesFunctionSelectorKey>
   getCXXMethodSelectorKey(ContextID CtxID, llvm::StringRef Name);
@@ -180,6 +186,12 @@ class APINotesReader {
   getCXXMethodSelectorKey(ContextID CtxID, llvm::StringRef Name,
                           llvm::ArrayRef<std::string> Parameters);
 
+  /// Build the selector key for the given C++ method with a composed
+  /// selector.
+  std::optional<APINotesFunctionSelectorKey>
+  getCXXMethodSelectorKey(ContextID CtxID, llvm::StringRef Name,
+                          const FunctionSelector &Selector);
+
   /// Look for information regarding the given global variable.
   ///
   /// \param Name The name of the global variable.
@@ -218,8 +230,9 @@ class APINotesReader {
                                llvm::ArrayRef<std::string> Parameters,
                                std::optional<Context> Ctx = std::nullopt);
 
-  /// Collect exact parameter selector keys stored by this reader.
-  void collectExactFunctionParameterSelectors(
+  /// Collect selector keys stored by this reader that should be diagnosed if
+  /// unmatched.
+  void collectFunctionSelectorsForDiagnostics(
       llvm::SmallVectorImpl<APINotesFunctionSelectorKey> &Selectors);
 
   /// Reconstruct parameter selector strings for a stored exact selector key.
@@ -275,10 +288,9 @@ class APINotesReader {
 private:
   VersionedInfo<CXXMethodInfo> lookupCXXMethodImpl(ContextID CtxID,
                                                    llvm::StringRef Name);
-  template <typename ParameterT>
   VersionedInfo<CXXMethodInfo>
   lookupCXXMethodImpl(ContextID CtxID, llvm::StringRef Name,
-                      llvm::ArrayRef<ParameterT> Parameters);
+                      const FunctionSelector &Selector);
 
   VersionedInfo<GlobalFunctionInfo>
   lookupGlobalFunctionImpl(llvm::StringRef Name, std::optional<Context> Ctx);
diff --git a/clang/include/clang/APINotes/APINotesWriter.h 
b/clang/include/clang/APINotes/APINotesWriter.h
index 5ed6686e1bb85..c0d07ceeb30cc 100644
--- a/clang/include/clang/APINotes/APINotesWriter.h
+++ b/clang/include/clang/APINotes/APINotesWriter.h
@@ -95,6 +95,12 @@ class APINotesWriter {
                     llvm::ArrayRef<llvm::StringRef> Parameters,
                     const CXXMethodInfo &Info, llvm::VersionTuple 
SwiftVersion);
 
+  /// Add information about a C++ method with a composed selector. Omitted
+  /// selector components use the broad name-based key.
+  void addCXXMethod(ContextID CtxID, llvm::StringRef Name,
+                    const FunctionSelector &Selector, 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.
diff --git a/clang/include/clang/APINotes/Types.h 
b/clang/include/clang/APINotes/Types.h
index af989d3a1b7f0..4151e26a98b45 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -1008,19 +1008,132 @@ struct Context {
 
 using IdentifierID = llvm::PointerEmbeddedInt<unsigned, 31>;
 
+/// Describes the C++ implicit-object ref-qualifier portion of a method
+/// selector.
+enum class FunctionObjectRefQualifier : uint8_t {
+  None,
+  LValue,
+  RValue,
+};
+
+/// Describes optional constraints on a C++ method's implicit object parameter.
+struct FunctionObjectSelector {
+  std::optional<bool> Const;
+  std::optional<bool> Volatile;
+  std::optional<FunctionObjectRefQualifier> Ref;
+};
+
+inline bool operator==(const FunctionObjectSelector &LHS,
+                       const FunctionObjectSelector &RHS) {
+  return LHS.Const == RHS.Const && LHS.Volatile == RHS.Volatile &&
+         LHS.Ref == RHS.Ref;
+}
+
+inline bool operator!=(const FunctionObjectSelector &LHS,
+                       const FunctionObjectSelector &RHS) {
+  return !(LHS == RHS);
+}
+
+inline std::string formatAPINotesObjectSelector(FunctionObjectSelector Object) 
{
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+  llvm::SmallVector<std::string, 3> Parts;
+
+  if (Object.Const)
+    Parts.push_back(std::string("Const: ") +
+                    (*Object.Const ? "true" : "false"));
+  if (Object.Volatile)
+    Parts.push_back(std::string("Volatile: ") +
+                    (*Object.Volatile ? "true" : "false"));
+  if (Object.Ref) {
+    std::string Ref = "Ref: ";
+    switch (*Object.Ref) {
+    case FunctionObjectRefQualifier::None:
+      Ref += "none";
+      break;
+    case FunctionObjectRefQualifier::LValue:
+      Ref += "lvalue";
+      break;
+    case FunctionObjectRefQualifier::RValue:
+      Ref += "rvalue";
+      break;
+    }
+    Parts.push_back(Ref);
+  }
+
+  OS << "Object{";
+  llvm::interleaveComma(Parts, OS);
+  OS << "}";
+  return Result;
+}
+
+/// Describes a C++ function selector composed from optional exact explicit
+/// parameters plus optional implicit object constraints.
+struct FunctionSelector {
+  std::optional<llvm::SmallVector<std::string, 4>> Parameters;
+  std::optional<FunctionObjectSelector> Object;
+};
+
+inline bool operator==(const FunctionSelector &LHS,
+                       const FunctionSelector &RHS) {
+  return LHS.Parameters == RHS.Parameters && LHS.Object == RHS.Object;
+}
+
+inline bool operator!=(const FunctionSelector &LHS,
+                       const FunctionSelector &RHS) {
+  return !(LHS == RHS);
+}
+
+inline std::string formatAPINotesFunctionSelector(
+    std::optional<llvm::ArrayRef<std::string>> Parameters,
+    std::optional<FunctionObjectSelector> Object) {
+  std::string Result;
+  if (Parameters)
+    Result = (llvm::Twine("Where.Parameters ") +
+              formatAPINotesParameterSelector(*Parameters))
+                 .str();
+
+  if (Object) {
+    if (!Result.empty())
+      Result += " ";
+    else
+      Result = "Where.Object ";
+    Result += formatAPINotesObjectSelector(*Object);
+  }
+
+  return Result;
+}
+
+inline std::string
+formatAPINotesFunctionSelector(const FunctionSelector &Selector) {
+  std::optional<llvm::ArrayRef<std::string>> Parameters;
+  if (Selector.Parameters)
+    Parameters = llvm::ArrayRef<std::string>(*Selector.Parameters);
+  return formatAPINotesFunctionSelector(Parameters, Selector.Object);
+}
+
+struct FunctionTableSelectorKey {
+  std::optional<llvm::SmallVector<IdentifierID, 2>> Parameters;
+  std::optional<FunctionObjectSelector> Object;
+};
+
 /// A key for a stored global-function or C++-method API notes entry.
 ///
 /// The key is represented by the ID of its parent context, the declaration
-/// name, and optional exact parameter types.
+/// name, and optional exact parameter/object selector data.
 struct FunctionTableKey {
   uint32_t parentContextID;
   uint32_t nameID;
   std::optional<llvm::SmallVector<IdentifierID, 2>> parameterTypeIDs;
+  std::optional<FunctionObjectSelector> objectSelector;
 
   FunctionTableKey() : parentContextID(-1), nameID(-1) {}
 
-  FunctionTableKey(uint32_t ParentContextID, uint32_t NameID)
-      : parentContextID(ParentContextID), nameID(NameID) {}
+  FunctionTableKey(uint32_t ParentContextID, uint32_t NameID,
+                   FunctionTableSelectorKey Selector = {})
+      : parentContextID(ParentContextID), nameID(NameID),
+        parameterTypeIDs(std::move(Selector.Parameters)),
+        objectSelector(Selector.Object) {}
 
   FunctionTableKey(uint32_t ParentContextID, uint32_t NameID,
                    const llvm::SmallVectorImpl<IdentifierID> &ParameterTypeIDs)
@@ -1028,27 +1141,37 @@ struct FunctionTableKey {
     parameterTypeIDs.emplace(ParameterTypeIDs.begin(), ParameterTypeIDs.end());
   }
 
-  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,
+                   FunctionTableSelectorKey Selector = {})
+      : FunctionTableKey(ParentCtx ? ParentCtx->id.Value
+                                   : static_cast<uint32_t>(-1),
+                         NameID, std::move(Selector)) {}
 
   FunctionTableKey(std::optional<Context> ParentCtx, IdentifierID NameID,
                    const llvm::SmallVectorImpl<IdentifierID> &ParameterTypeIDs)
-      : parentContextID(ParentCtx ? ParentCtx->id.Value
-                                  : static_cast<uint32_t>(-1)),
-        nameID(NameID) {
+      : FunctionTableKey(ParentCtx ? ParentCtx->id.Value
+                                   : static_cast<uint32_t>(-1),
+                         NameID) {
     parameterTypeIDs.emplace(ParameterTypeIDs.begin(), ParameterTypeIDs.end());
   }
 
   llvm::hash_code hashValue() const {
     auto Hash = llvm::hash_combine(parentContextID, nameID,
-                                   static_cast<bool>(parameterTypeIDs));
+                                   static_cast<bool>(parameterTypeIDs),
+                                   static_cast<bool>(objectSelector));
     if (parameterTypeIDs) {
       Hash = llvm::hash_combine(Hash, parameterTypeIDs->size());
       for (IdentifierID TypeID : *parameterTypeIDs)
         Hash = llvm::hash_combine(Hash, static_cast<unsigned>(TypeID));
     }
+    if (objectSelector)
+      Hash = llvm::hash_combine(
+          Hash, objectSelector->Const.value_or(false),
+          static_cast<bool>(objectSelector->Const),
+          objectSelector->Volatile.value_or(false),
+          static_cast<bool>(objectSelector->Volatile),
+          objectSelector->Ref ? static_cast<unsigned>(*objectSelector->Ref) + 1
+                              : 0);
     return Hash;
   }
 };
@@ -1057,7 +1180,8 @@ inline bool operator==(const FunctionTableKey &LHS,
                        const FunctionTableKey &RHS) {
   return LHS.parentContextID == RHS.parentContextID &&
          LHS.nameID == RHS.nameID &&
-         LHS.parameterTypeIDs == RHS.parameterTypeIDs;
+         LHS.parameterTypeIDs == RHS.parameterTypeIDs &&
+         LHS.objectSelector == RHS.objectSelector;
 }
 
 /// Stable reader-facing identity for an API notes function selector entry.
@@ -1069,7 +1193,7 @@ struct APINotesFunctionSelectorKey {
   FunctionTableKey Key;
   bool IsCXXMethod = false;
 
-  APINotesFunctionSelectorKey getWithoutParameterSelector() const {
+  APINotesFunctionSelectorKey getNameOnlyKey() const {
     return {FunctionTableKey(Key.parentContextID, Key.nameID), IsCXXMethod};
   }
 
diff --git a/clang/lib/APINotes/APINotesFormat.h 
b/clang/lib/APINotes/APINotesFormat.h
index 30fc8599349bf..f0ea371e3ccef 100644
--- a/clang/lib/APINotes/APINotesFormat.h
+++ b/clang/lib/APINotes/APINotesFormat.h
@@ -16,6 +16,7 @@
 #include "llvm/Bitcode/BitcodeConvenience.h"
 
 #include <optional>
+#include <utility>
 
 namespace clang {
 namespace api_notes {
@@ -28,9 +29,10 @@ 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 = 41; // 39 for BoundsSafety;
+const uint16_t VERSION_MINOR = 42; // 39 for BoundsSafety;
                                    // 40 for UnsafeBufferUsageAttr
                                    // 41 for FunctionTableKey parameters
+                                   // 42 for FunctionTableKey object selectors
 
 const uint8_t kSwiftConforms = 1;
 const uint8_t kSwiftDoesNotConform = 2;
@@ -359,8 +361,21 @@ inline bool operator==(const SingleDeclTableKey &lhs,
 }
 
 /// 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.
+/// context, the name of the declaration, and optional exact parameter/object
+/// selector data.
 constexpr uint8_t FunctionKeyHasParameterSelector = 0x01;
+constexpr uint8_t FunctionKeyObjectConstPresent = 0x02;
+constexpr uint8_t FunctionKeyObjectConstValue = 0x04;
+constexpr uint8_t FunctionKeyObjectVolatilePresent = 0x08;
+constexpr uint8_t FunctionKeyObjectVolatileValue = 0x10;
+constexpr uint8_t FunctionKeyObjectRefPresent = 0x20;
+constexpr uint8_t FunctionKeyObjectRefLValue = 0x40;
+constexpr uint8_t FunctionKeyObjectRefRValue = 0x80;
+constexpr uint8_t FunctionKeyObjectSelectorMask =
+    FunctionKeyObjectConstPresent | FunctionKeyObjectConstValue |
+    FunctionKeyObjectVolatilePresent | FunctionKeyObjectVolatileValue |
+    FunctionKeyObjectRefPresent | FunctionKeyObjectRefLValue |
+    FunctionKeyObjectRefRValue;
 constexpr unsigned FunctionTableKeyBaseLength =
     sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint16_t);
 
@@ -375,10 +390,48 @@ getFunctionKeyImpl(uint32_t ParentContextID, 
llvm::StringRef Name,
   return FunctionTableKey(ParentContextID, *NameID);
 }
 
+template <typename GetIdentifierFn>
+std::optional<FunctionTableKey>
+getFunctionKeyImpl(uint32_t ParentContextID, llvm::StringRef Name,
+                   FunctionObjectSelector ObjectSelector,
+                   GetIdentifierFn GetIdentifier) {
+  std::optional<IdentifierID> NameID = GetIdentifier(Name);
+  if (!NameID)
+    return std::nullopt;
+
+  FunctionTableSelectorKey Selector;
+  Selector.Object = ObjectSelector;
+  return FunctionTableKey(ParentContextID, *NameID, std::move(Selector));
+}
+
+template <typename ParameterT, typename GetIdentifierFn>
+std::optional<FunctionTableKey>
+getFunctionKeyImpl(uint32_t ParentContextID, llvm::StringRef Name,
+                   llvm::ArrayRef<ParameterT> Parameters,
+                   GetIdentifierFn GetIdentifier) {
+  std::optional<IdentifierID> NameID = GetIdentifier(Name);
+  if (!NameID)
+    return std::nullopt;
+
+  llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs;
+  ParameterTypeIDs.reserve(Parameters.size());
+  for (const ParameterT &Parameter : Parameters) {
+    std::optional<IdentifierID> ParameterID =
+        GetIdentifier(llvm::StringRef(Parameter));
+    if (!ParameterID)
+      return std::nullopt;
+    ParameterTypeIDs.push_back(*ParameterID);
+  }
+  FunctionTableSelectorKey Selector;
+  Selector.Parameters.emplace(ParameterTypeIDs.begin(), 
ParameterTypeIDs.end());
+  return FunctionTableKey(ParentContextID, *NameID, std::move(Selector));
+}
+
 template <typename ParameterT, typename GetIdentifierFn>
 std::optional<FunctionTableKey>
 getFunctionKeyImpl(uint32_t ParentContextID, llvm::StringRef Name,
                    llvm::ArrayRef<ParameterT> Parameters,
+                   FunctionObjectSelector ObjectSelector,
                    GetIdentifierFn GetIdentifier) {
   std::optional<IdentifierID> NameID = GetIdentifier(Name);
   if (!NameID)
@@ -393,7 +446,10 @@ getFunctionKeyImpl(uint32_t ParentContextID, 
llvm::StringRef Name,
       return std::nullopt;
     ParameterTypeIDs.push_back(*ParameterID);
   }
-  return FunctionTableKey(ParentContextID, *NameID, ParameterTypeIDs);
+  FunctionTableSelectorKey Selector;
+  Selector.Parameters.emplace(ParameterTypeIDs.begin(), 
ParameterTypeIDs.end());
+  Selector.Object = ObjectSelector;
+  return FunctionTableKey(ParentContextID, *NameID, std::move(Selector));
 }
 
 } // namespace api_notes
diff --git a/clang/lib/APINotes/APINotesReader.cpp 
b/clang/lib/APINotes/APINotesReader.cpp
index aad597d93d9ee..ab06d75826d1a 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -72,14 +72,47 @@ static FunctionTableKey readFunctionTableKey(const uint8_t 
*Data,
     ParameterTypeIDs.push_back(
         endian::readNext<uint32_t, llvm::endianness::little>(Data));
 
-  assert((FunctionKeyFlags & ~FunctionKeyHasParameterSelector) == 0 &&
-         "Unexpected function table key flags");
+  if (FunctionKeyFlags & FunctionKeyObjectRefLValue)
+    assert(!(FunctionKeyFlags & FunctionKeyObjectRefRValue) &&
+           "Unexpected function table key ref qualifier flags");
+  assert(((FunctionKeyFlags & FunctionKeyObjectConstValue) == 0 ||
+          (FunctionKeyFlags & FunctionKeyObjectConstPresent)) &&
+         "Function table key const value requires presence flag");
+  assert(((FunctionKeyFlags & FunctionKeyObjectVolatileValue) == 0 ||
+          (FunctionKeyFlags & FunctionKeyObjectVolatilePresent)) &&
+         "Function table key volatile value requires presence flag");
+  assert(((FunctionKeyFlags &
+           (FunctionKeyObjectRefLValue | FunctionKeyObjectRefRValue)) == 0 ||
+          (FunctionKeyFlags & FunctionKeyObjectRefPresent)) &&
+         "Function table key ref value requires presence flag");
+  std::optional<FunctionObjectSelector> ObjectSelector;
+  if (FunctionKeyFlags & FunctionKeyObjectSelectorMask) {
+    FunctionObjectSelector Selector;
+    if (FunctionKeyFlags & FunctionKeyObjectConstPresent)
+      Selector.Const = (FunctionKeyFlags & FunctionKeyObjectConstValue) != 0;
+    if (FunctionKeyFlags & FunctionKeyObjectVolatilePresent)
+      Selector.Volatile =
+          (FunctionKeyFlags & FunctionKeyObjectVolatileValue) != 0;
+    if (FunctionKeyFlags & FunctionKeyObjectRefPresent) {
+      if (FunctionKeyFlags & FunctionKeyObjectRefLValue)
+        Selector.Ref = FunctionObjectRefQualifier::LValue;
+      else if (FunctionKeyFlags & FunctionKeyObjectRefRValue)
+        Selector.Ref = FunctionObjectRefQualifier::RValue;
+      else
+        Selector.Ref = FunctionObjectRefQualifier::None;
+    }
+    ObjectSelector = Selector;
+  }
+
+  FunctionTableSelectorKey Selector;
   if (FunctionKeyFlags & FunctionKeyHasParameterSelector)
-    return {CtxID, NameID, ParameterTypeIDs};
-
-  assert(ParameterTypeIDs.empty() &&
-         "Broad function table key should not store parameters");
-  return {CtxID, NameID};
+    Selector.Parameters.emplace(ParameterTypeIDs.begin(),
+                                ParameterTypeIDs.end());
+  else
+    assert(ParameterTypeIDs.empty() &&
+           "Broad function table key should not store parameters");
+  Selector.Object = ObjectSelector;
+  return FunctionTableKey(CtxID, NameID, std::move(Selector));
 }
 
 /// An on-disk hash table whose data is versioned based on the Swift version.
@@ -844,10 +877,10 @@ class APINotesReader::Implementation {
   /// the ID is unknown.
   std::optional<llvm::StringRef> getIdentifierString(IdentifierID ID);
 
-  /// Collect exact parameter selector keys stored in the given function-like
-  /// table.
+  /// Collect selector keys stored in the given function-like table that
+  /// should be diagnosed if unmatched.
   template <typename TableT>
-  void collectExactFunctionParameterSelectors(
+  void collectFunctionSelectorsForDiagnostics(
       TableT &Table,
       llvm::SmallVectorImpl<APINotesFunctionSelectorKey> &Selectors);
 
@@ -880,11 +913,17 @@ class APINotesReader::Implementation {
   getFunctionKey(uint32_t ParentContextID, llvm::StringRef Name,
                  llvm::ArrayRef<ParameterT> Parameters);
   std::optional<FunctionTableKey>
+  getFunctionKey(uint32_t ParentContextID, llvm::StringRef Name,
+                 const FunctionSelector &Selector);
+  std::optional<FunctionTableKey>
   getFunctionKey(std::optional<Context> ParentContext, llvm::StringRef Name);
   template <typename ParameterT>
   std::optional<FunctionTableKey>
   getFunctionKey(std::optional<Context> ParentContext, llvm::StringRef Name,
                  llvm::ArrayRef<ParameterT> Parameters);
+  std::optional<FunctionTableKey>
+  getFunctionKey(std::optional<Context> ParentContext, llvm::StringRef Name,
+                 const FunctionSelector &Selector);
 
   llvm::Error readGlobalFunctionBlock(llvm::BitstreamCursor &Cursor,
                                       llvm::SmallVectorImpl<uint64_t> 
&Scratch);
@@ -944,7 +983,7 @@ 
APINotesReader::Implementation::getIdentifierString(IdentifierID ID) {
 }
 
 template <typename TableT>
-void APINotesReader::Implementation::collectExactFunctionParameterSelectors(
+void APINotesReader::Implementation::collectFunctionSelectorsForDiagnostics(
     TableT &Table,
     llvm::SmallVectorImpl<APINotesFunctionSelectorKey> &Selectors) {
   static_assert(std::is_same_v<TableT, SerializedGlobalFunctionTable> ||
@@ -952,7 +991,7 @@ void 
APINotesReader::Implementation::collectExactFunctionParameterSelectors(
   constexpr bool IsCXXMethod = std::is_same_v<TableT, 
SerializedCXXMethodTable>;
 
   for (const FunctionTableKey &Key : Table.keys()) {
-    if (!Key.parameterTypeIDs)
+    if (!Key.parameterTypeIDs && !Key.objectSelector)
       continue;
 
     Selectors.push_back(APINotesFunctionSelectorKey{Key, IsCXXMethod});
@@ -976,6 +1015,26 @@ std::optional<FunctionTableKey> 
APINotesReader::Implementation::getFunctionKey(
       [this](llvm::StringRef S) { return getIdentifier(S); });
 }
 
+std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
+    uint32_t ParentContextID, llvm::StringRef Name,
+    const FunctionSelector &Selector) {
+  auto GetIdentifier = [this](llvm::StringRef S) { return getIdentifier(S); };
+  if (Selector.Parameters) {
+    if (Selector.Object)
+      return getFunctionKeyImpl(
+          ParentContextID, Name,
+          llvm::ArrayRef<std::string>(*Selector.Parameters), *Selector.Object,
+          GetIdentifier);
+    return getFunctionKeyImpl(ParentContextID, Name,
+                              
llvm::ArrayRef<std::string>(*Selector.Parameters),
+                              GetIdentifier);
+  }
+  if (Selector.Object)
+    return getFunctionKeyImpl(ParentContextID, Name, *Selector.Object,
+                              GetIdentifier);
+  return getFunctionKeyImpl(ParentContextID, Name, GetIdentifier);
+}
+
 std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
     std::optional<Context> ParentContext, llvm::StringRef Name) {
   uint32_t ParentContextID =
@@ -992,6 +1051,14 @@ std::optional<FunctionTableKey> 
APINotesReader::Implementation::getFunctionKey(
   return getFunctionKey(ParentContextID, Name, Parameters);
 }
 
+std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
+    std::optional<Context> ParentContext, llvm::StringRef Name,
+    const FunctionSelector &Selector) {
+  uint32_t ParentContextID =
+      ParentContext ? ParentContext->id.Value : static_cast<uint32_t>(-1);
+  return getFunctionKey(ParentContextID, Name, Selector);
+}
+
 std::optional<SelectorID>
 APINotesReader::Implementation::getSelector(ObjCSelectorRef Selector) {
   if (!ObjCSelectorTable || !IdentifierTable)
@@ -2414,7 +2481,15 @@ auto APINotesReader::lookupCXXMethod(ContextID CtxID, 
llvm::StringRef Name)
 auto APINotesReader::lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
                                      llvm::ArrayRef<std::string> Parameters)
     -> VersionedInfo<CXXMethodInfo> {
-  return lookupCXXMethodImpl(CtxID, Name, Parameters);
+  FunctionSelector Selector;
+  Selector.Parameters.emplace(Parameters.begin(), Parameters.end());
+  return lookupCXXMethodImpl(CtxID, Name, Selector);
+}
+
+auto APINotesReader::lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
+                                     const FunctionSelector &Selector)
+    -> VersionedInfo<CXXMethodInfo> {
+  return lookupCXXMethodImpl(CtxID, Name, Selector);
 }
 
 std::optional<APINotesFunctionSelectorKey>
@@ -2437,6 +2512,16 @@ APINotesReader::getCXXMethodSelectorKey(
   return APINotesFunctionSelectorKey{*Key, /*IsCXXMethod=*/true};
 }
 
+std::optional<APINotesFunctionSelectorKey>
+APINotesReader::getCXXMethodSelectorKey(ContextID CtxID, llvm::StringRef Name,
+                                        const FunctionSelector &Selector) {
+  std::optional<FunctionTableKey> Key =
+      Implementation->getFunctionKey(CtxID.Value, Name, Selector);
+  if (!Key)
+    return std::nullopt;
+  return APINotesFunctionSelectorKey{*Key, /*IsCXXMethod=*/true};
+}
+
 auto APINotesReader::lookupCXXMethodImpl(ContextID CtxID, llvm::StringRef Name)
     -> VersionedInfo<CXXMethodInfo> {
   if (!Implementation->CXXMethodTable)
@@ -2454,15 +2539,14 @@ auto APINotesReader::lookupCXXMethodImpl(ContextID 
CtxID, llvm::StringRef Name)
   return {Implementation->SwiftVersion, *Known};
 }
 
-template <typename ParameterT>
 auto APINotesReader::lookupCXXMethodImpl(ContextID CtxID, llvm::StringRef Name,
-                                         llvm::ArrayRef<ParameterT> Parameters)
+                                         const FunctionSelector &Selector)
     -> VersionedInfo<CXXMethodInfo> {
   if (!Implementation->CXXMethodTable)
     return std::nullopt;
 
   std::optional<FunctionTableKey> Key =
-      Implementation->getFunctionKey(CtxID.Value, Name, Parameters);
+      Implementation->getFunctionKey(CtxID.Value, Name, Selector);
   if (!Key)
     return std::nullopt;
 
@@ -2525,13 +2609,13 @@ APINotesReader::getGlobalFunctionSelectorKey(
   return APINotesFunctionSelectorKey{*Key, /*IsCXXMethod=*/false};
 }
 
-void APINotesReader::collectExactFunctionParameterSelectors(
+void APINotesReader::collectFunctionSelectorsForDiagnostics(
     llvm::SmallVectorImpl<APINotesFunctionSelectorKey> &Selectors) {
   if (Implementation->GlobalFunctionTable)
-    Implementation->collectExactFunctionParameterSelectors(
+    Implementation->collectFunctionSelectorsForDiagnostics(
         *Implementation->GlobalFunctionTable, Selectors);
   if (Implementation->CXXMethodTable)
-    Implementation->collectExactFunctionParameterSelectors(
+    Implementation->collectFunctionSelectorsForDiagnostics(
         *Implementation->CXXMethodTable, Selectors);
 }
 
diff --git a/clang/lib/APINotes/APINotesWriter.cpp 
b/clang/lib/APINotes/APINotesWriter.cpp
index 86fee93ec4765..4027d096bf02a 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -158,6 +158,32 @@ class APINotesWriter::Implementation {
     return *Key;
   }
 
+  FunctionTableKey getFunctionKey(uint32_t ParentContextID, StringRef Name,
+                                  const FunctionSelector &Selector) {
+    std::optional<FunctionTableKey> Key;
+    auto GetIdentifier = [this](StringRef S) -> std::optional<IdentifierID> {
+      return getIdentifier(S);
+    };
+    if (Selector.Parameters) {
+      if (Selector.Object)
+        Key = getFunctionKeyImpl(
+            ParentContextID, Name,
+            llvm::ArrayRef<std::string>(*Selector.Parameters), 
*Selector.Object,
+            GetIdentifier);
+      else
+        Key = getFunctionKeyImpl(
+            ParentContextID, Name,
+            llvm::ArrayRef<std::string>(*Selector.Parameters), GetIdentifier);
+    } else if (Selector.Object) {
+      Key = getFunctionKeyImpl(ParentContextID, Name, *Selector.Object,
+                               GetIdentifier);
+    } else {
+      Key = getFunctionKeyImpl(ParentContextID, Name, GetIdentifier);
+    }
+    assert(Key && "Writer identifier lookup should not fail");
+    return *Key;
+  }
+
   FunctionTableKey getFunctionKey(std::optional<Context> ParentContext,
                                   StringRef Name) {
     uint32_t ParentContextID =
@@ -173,6 +199,14 @@ class APINotesWriter::Implementation {
     return getFunctionKey(ParentContextID, Name, Parameters);
   }
 
+  FunctionTableKey getFunctionKey(std::optional<Context> ParentContext,
+                                  StringRef Name,
+                                  const FunctionSelector &Selector) {
+    uint32_t ParentContextID =
+        ParentContext ? ParentContext->id.Value : static_cast<uint32_t>(-1);
+    return getFunctionKey(ParentContextID, Name, Selector);
+  }
+
   /// Retrieve the ID for the given selector.
   SelectorID getSelector(ObjCSelectorRef SelectorRef) {
     // Translate the selector reference into a stored selector.
@@ -507,12 +541,42 @@ static unsigned getFunctionTableKeyLength(const 
FunctionTableKey &Key) {
                                : 0);
 }
 
+static uint8_t getFunctionTableKeyFlags(const FunctionTableKey &Key) {
+  uint8_t Flags = Key.parameterTypeIDs ? FunctionKeyHasParameterSelector : 0;
+  if (!Key.objectSelector)
+    return Flags;
+
+  if (Key.objectSelector->Const) {
+    Flags |= FunctionKeyObjectConstPresent;
+    if (*Key.objectSelector->Const)
+      Flags |= FunctionKeyObjectConstValue;
+  }
+  if (Key.objectSelector->Volatile) {
+    Flags |= FunctionKeyObjectVolatilePresent;
+    if (*Key.objectSelector->Volatile)
+      Flags |= FunctionKeyObjectVolatileValue;
+  }
+  if (Key.objectSelector->Ref) {
+    Flags |= FunctionKeyObjectRefPresent;
+    switch (*Key.objectSelector->Ref) {
+    case FunctionObjectRefQualifier::None:
+      break;
+    case FunctionObjectRefQualifier::LValue:
+      Flags |= FunctionKeyObjectRefLValue;
+      break;
+    case FunctionObjectRefQualifier::RValue:
+      Flags |= FunctionKeyObjectRefRValue;
+      break;
+    }
+  }
+  return Flags;
+}
+
 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<uint8_t>(getFunctionTableKeyFlags(Key));
   writer.write<uint16_t>(Key.parameterTypeIDs ? Key.parameterTypeIDs->size()
                                               : 0);
   if (Key.parameterTypeIDs)
@@ -1631,6 +1695,15 @@ void APINotesWriter::addCXXMethod(ContextID CtxID, 
llvm::StringRef Name,
   Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
 }
 
+void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,
+                                  const FunctionSelector &Selector,
+                                  const CXXMethodInfo &Info,
+                                  VersionTuple SwiftVersion) {
+  FunctionTableKey Key =
+      Implementation->getFunctionKey(CtxID.Value, Name, Selector);
+  Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
+}
+
 void APINotesWriter::addField(ContextID CtxID, llvm::StringRef Name,
                               const FieldInfo &Info,
                               VersionTuple SwiftVersion) {
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp 
b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index 4079675228a21..608152b2f4442 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -18,7 +18,6 @@
 #include "clang/APINotes/Types.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/Specifiers.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringSet.h"
@@ -347,6 +346,7 @@ typedef std::vector<StringRef> WhereParamsSeq;
 
 struct FunctionWhere {
   std::optional<WhereParamsSeq> Parameters;
+  std::optional<api_notes::FunctionObjectSelector> Object;
 };
 
 struct Function {
@@ -373,9 +373,27 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(Function)
 
 namespace llvm {
 namespace yaml {
+template <>
+struct ScalarEnumerationTraits<api_notes::FunctionObjectRefQualifier> {
+  static void enumeration(IO &IO, api_notes::FunctionObjectRefQualifier &Ref) {
+    IO.enumCase(Ref, "none", api_notes::FunctionObjectRefQualifier::None);
+    IO.enumCase(Ref, "lvalue", api_notes::FunctionObjectRefQualifier::LValue);
+    IO.enumCase(Ref, "rvalue", api_notes::FunctionObjectRefQualifier::RValue);
+  }
+};
+
+template <> struct MappingTraits<api_notes::FunctionObjectSelector> {
+  static void mapping(IO &IO, api_notes::FunctionObjectSelector &O) {
+    IO.mapOptional("Const", O.Const);
+    IO.mapOptional("Volatile", O.Volatile);
+    IO.mapOptional("Ref", O.Ref);
+  }
+};
+
 template <> struct MappingTraits<FunctionWhere> {
   static void mapping(IO &IO, FunctionWhere &W) {
     IO.mapOptional("Parameters", W.Parameters);
+    IO.mapOptional("Object", W.Object);
   }
 };
 
@@ -793,19 +811,20 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI,
 namespace {
 using namespace api_notes;
 
+static void appendDuplicateKeyPart(llvm::raw_ostream &OS,
+                                   llvm::StringRef Part) {
+  OS << Part.size() << ':' << Part;
+}
+
 static std::string
-getFunctionSelectorKey(llvm::StringRef Name,
-                       llvm::ArrayRef<llvm::StringRef> Parameters) {
+getFunctionSelectorDuplicateKey(llvm::StringRef Name,
+                                const FunctionSelector &Selector) {
   llvm::SmallString<64> Key;
   llvm::raw_svector_ostream OS(Key);
-  auto AppendKeyPart = [&OS](llvm::StringRef Part) {
-    OS << Part.size() << ':' << Part;
-  };
-
-  AppendKeyPart(Name);
-  OS << ';';
-  for (llvm::StringRef Parameter : Parameters)
-    AppendKeyPart(Parameter);
+  appendDuplicateKeyPart(OS, Name);
+  std::string SelectorText =
+      api_notes::formatAPINotesFunctionSelector(Selector);
+  appendDuplicateKeyPart(OS, SelectorText);
   return Key.str().str();
 }
 
@@ -1064,16 +1083,38 @@ class YAMLConverter {
                          TheNamespace.Items, SwiftVersion);
   }
 
-  std::pair<bool, std::optional<llvm::ArrayRef<llvm::StringRef>>>
-  getWhereParameters(const Function &Function) {
+  std::optional<FunctionSelector> getWhereSelector(const Function &Function,
+                                                   bool AllowObject) {
     if (!Function.Where)
-      return {true, std::nullopt};
+      return FunctionSelector{};
+
+    if (!Function.Where->Parameters && !Function.Where->Object) {
+      emitError("'Where' requires 'Parameters' or 'Object'");
+      return std::nullopt;
+    }
+
+    FunctionSelector Selector;
+    if (Function.Where->Parameters) {
+      Selector.Parameters.emplace();
+      Selector.Parameters->reserve(Function.Where->Parameters->size());
+      for (llvm::StringRef Parameter : *Function.Where->Parameters)
+        Selector.Parameters->push_back(Parameter.str());
+    }
 
-    if (!Function.Where->Parameters) {
-      emitError("'Where' requires 'Parameters'");
-      return {false, std::nullopt};
+    if (Function.Where->Object) {
+      if (!AllowObject) {
+        emitError("'Object' is only supported on C++ methods");
+        return std::nullopt;
+      }
+      if (!Function.Where->Object->Const && !Function.Where->Object->Volatile 
&&
+          !Function.Where->Object->Ref) {
+        emitError("'Object' requires at least one field");
+        return std::nullopt;
+      }
+      Selector.Object = Function.Where->Object;
     }
-    return {true, 
llvm::ArrayRef<llvm::StringRef>(*Function.Where->Parameters)};
+
+    return Selector;
   }
 
   template <typename FuncOrMethodInfo>
@@ -1185,27 +1226,26 @@ class YAMLConverter {
 
     llvm::StringSet<> KnownMethodSelectors;
     for (const auto &CXXMethod : T.Methods) {
-      auto WhereParameters = getWhereParameters(CXXMethod);
-      if (!WhereParameters.first)
+      auto WhereSelector = getWhereSelector(CXXMethod, /*AllowObject=*/true);
+      if (!WhereSelector)
         continue;
 
-      if (WhereParameters.second) {
-        if (!KnownMethodSelectors
-                 .insert(getFunctionSelectorKey(CXXMethod.Name,
-                                                *WhereParameters.second))
-                 .second) {
+      if (WhereSelector->Parameters || WhereSelector->Object) {
+        std::string DuplicateKey =
+            getFunctionSelectorDuplicateKey(CXXMethod.Name, *WhereSelector);
+        if (!KnownMethodSelectors.insert(DuplicateKey).second) {
           emitError(llvm::Twine("multiple API notes entries for C++ method '") 
+
-                    CXXMethod.Name + "' with Where.Parameters " +
-                    formatAPINotesParameterSelector(*WhereParameters.second));
+                    CXXMethod.Name + "' with " +
+                    api_notes::formatAPINotesFunctionSelector(*WhereSelector));
           continue;
         }
       }
 
       CXXMethodInfo MI;
       convertFunction(CXXMethod, MI);
-      if (WhereParameters.second)
-        Writer.addCXXMethod(TagCtxID, CXXMethod.Name, *WhereParameters.second,
-                            MI, SwiftVersion);
+      if (WhereSelector->Parameters || WhereSelector->Object)
+        Writer.addCXXMethod(TagCtxID, CXXMethod.Name, *WhereSelector, MI,
+                            SwiftVersion);
       else
         Writer.addCXXMethod(TagCtxID, CXXMethod.Name, MI, SwiftVersion);
     }
@@ -1279,25 +1319,24 @@ class YAMLConverter {
     llvm::StringSet<> KnownNameOnlyFunctions;
     llvm::StringSet<> KnownFunctionSelectors;
     for (const auto &Function : TLItems.Functions) {
-      auto WhereParameters = getWhereParameters(Function);
-      if (!WhereParameters.first)
+      auto WhereSelector = getWhereSelector(Function, /*AllowObject=*/false);
+      if (!WhereSelector)
         continue;
 
-      if (WhereParameters.second) {
-        if (!KnownFunctionSelectors
-                 .insert(getFunctionSelectorKey(Function.Name,
-                                                *WhereParameters.second))
-                 .second) {
+      if (WhereSelector->Parameters) {
+        std::string DuplicateKey =
+            getFunctionSelectorDuplicateKey(Function.Name, *WhereSelector);
+        if (!KnownFunctionSelectors.insert(DuplicateKey).second) {
           emitError(
               llvm::Twine("multiple API notes entries for global function '") +
-              Function.Name + "' with Where.Parameters " +
-              formatAPINotesParameterSelector(*WhereParameters.second));
+              Function.Name + "' with " +
+              api_notes::formatAPINotesFunctionSelector(*WhereSelector));
           continue;
         }
       }
 
       // Check for duplicate name-only global functions.
-      if (!WhereParameters.second &&
+      if (!WhereSelector->Parameters &&
           !KnownNameOnlyFunctions.insert(Function.Name).second) {
         emitError(llvm::Twine("multiple definitions of global function '") +
                   Function.Name + "'");
@@ -1306,11 +1345,16 @@ class YAMLConverter {
 
       GlobalFunctionInfo GFI;
       convertFunction(Function, GFI);
-      if (WhereParameters.second)
-        Writer.addGlobalFunction(Ctx, Function.Name, *WhereParameters.second,
-                                 GFI, SwiftVersion);
-      else
+      if (WhereSelector->Parameters) {
+        llvm::SmallVector<llvm::StringRef, 4> ParameterRefs;
+        ParameterRefs.reserve(WhereSelector->Parameters->size());
+        for (const std::string &Parameter : *WhereSelector->Parameters)
+          ParameterRefs.push_back(Parameter);
+        Writer.addGlobalFunction(Ctx, Function.Name, ParameterRefs, GFI,
+                                 SwiftVersion);
+      } else {
         Writer.addGlobalFunction(Ctx, Function.Name, GFI, SwiftVersion);
+      }
     }
 
     // Write all enumerators.
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 78153d9ddf39d..e7ddacf9d2515 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -23,6 +23,7 @@
 #include "clang/Lex/Lexer.h"
 #include "clang/Sema/SemaObjC.h"
 #include "clang/Sema/SemaSwift.h"
+#include "llvm/ADT/bit.h"
 #include <stack>
 
 using namespace clang;
@@ -1085,7 +1086,7 @@ APINotesSelectorDiagnosticState::getOrCreateReaderState(
     return State;
 
   SmallVector<api_notes::APINotesFunctionSelectorKey, 4> Selectors;
-  Reader.collectExactFunctionParameterSelectors(Selectors);
+  Reader.collectFunctionSelectorsForDiagnostics(Selectors);
   State.addSelectors(Selectors);
   return State;
 }
@@ -1112,6 +1113,58 @@ void 
APINotesSelectorDiagnosticReaderState::markCandidatesUsed(
   }
 }
 
+static api_notes::FunctionObjectSelector
+getAPINotesObjectSelector(const CXXMethodDecl *Method) {
+  api_notes::FunctionObjectSelector Selector;
+  Selector.Const = Method->isConst();
+  Selector.Volatile = Method->isVolatile();
+  switch (Method->getRefQualifier()) {
+  case RQ_None:
+    Selector.Ref = api_notes::FunctionObjectRefQualifier::None;
+    break;
+  case RQ_LValue:
+    Selector.Ref = api_notes::FunctionObjectRefQualifier::LValue;
+    break;
+  case RQ_RValue:
+    Selector.Ref = api_notes::FunctionObjectRefQualifier::RValue;
+    break;
+  }
+  return Selector;
+}
+
+static void getAPINotesObjectSelectorSubsets(
+    api_notes::FunctionObjectSelector ObjectSelector,
+    SmallVectorImpl<api_notes::FunctionObjectSelector> &Subsets) {
+  enum ObjectSelectorField : unsigned {
+    ConstField = 1u << 0,
+    VolatileField = 1u << 1,
+    RefField = 1u << 2,
+  };
+
+  constexpr unsigned ObjectSelectorSubsetMasks[] = {
+      ConstField,
+      VolatileField,
+      RefField,
+      ConstField | VolatileField,
+      ConstField | RefField,
+      VolatileField | RefField,
+      ConstField | VolatileField | RefField,
+  };
+
+  // Apply less-constrained object selectors before more-constrained ones so
+  // entries that specify more Object fields can refine earlier effects.
+  for (unsigned Mask : ObjectSelectorSubsetMasks) {
+    api_notes::FunctionObjectSelector Subset;
+    if (Mask & ConstField)
+      Subset.Const = ObjectSelector.Const;
+    if (Mask & VolatileField)
+      Subset.Volatile = ObjectSelector.Volatile;
+    if (Mask & RefField)
+      Subset.Ref = ObjectSelector.Ref;
+    Subsets.push_back(Subset);
+  }
+}
+
 // Apply the first exact selector entry found. This preserves source-spelling
 // precedence over the desugared fallback and avoids applying multiple exact
 // entries for the same declaration.
@@ -1397,21 +1450,20 @@ void Sema::ProcessAPINotes(Decl *D) {
             auto Info = Reader->lookupCXXMethod(Context->id, MethodName);
             ProcessVersionedAPINotes(*this, CXXMethod, Info);
 
-            if (ParameterSelectorCandidates)
+            auto &DiagnosticState =
+                getAPINotesSelectorDiagnosticState(*this, Reader);
+            if (auto NameOnlyKey =
+                    Reader->getCXXMethodSelectorKey(Context->id, MethodName))
+              DiagnosticState.noteSeenDeclaration(*NameOnlyKey, MethodName,
+                                                  CXXMethod->getLocation());
+
+            if (ParameterSelectorCandidates) {
               processExactAPINotes<api_notes::CXXMethodInfo>(
                   *this, CXXMethod, *ParameterSelectorCandidates,
                   [&](ArrayRef<std::string> Parameters) {
                     return Reader->lookupCXXMethod(Context->id, MethodName,
                                                    Parameters);
                   });
-
-            if (ParameterSelectorCandidates) {
-              auto &DiagnosticState =
-                  getAPINotesSelectorDiagnosticState(*this, Reader);
-              if (auto BroadKey =
-                      Reader->getCXXMethodSelectorKey(Context->id, MethodName))
-                DiagnosticState.noteSeenDeclaration(*BroadKey, MethodName,
-                                                    CXXMethod->getLocation());
               DiagnosticState.markCandidatesUsed(
                   [&](ArrayRef<std::string> Parameters) {
                     return Reader->getCXXMethodSelectorKey(
@@ -1419,6 +1471,52 @@ void Sema::ProcessAPINotes(Decl *D) {
                   },
                   *ParameterSelectorCandidates);
             }
+
+            if (!CXXMethod->isStatic()) {
+              SmallVector<api_notes::FunctionObjectSelector, 7> 
ObjectSelectors;
+              getAPINotesObjectSelectorSubsets(
+                  getAPINotesObjectSelector(CXXMethod), ObjectSelectors);
+              // Apply every matching object selector in increasing 
specificity.
+              // Wildcard object constraints are broad refinements. Selectors
+              // that also constrain explicit parameters are applied last.
+              for (api_notes::FunctionObjectSelector ObjectSelector :
+                   ObjectSelectors) {
+                api_notes::FunctionSelector Selector;
+                Selector.Object = ObjectSelector;
+                auto ObjectInfo =
+                    Reader->lookupCXXMethod(Context->id, MethodName, Selector);
+                ProcessVersionedAPINotes(*this, CXXMethod, ObjectInfo);
+                if (auto ObjectKey = Reader->getCXXMethodSelectorKey(
+                        Context->id, MethodName, Selector))
+                  DiagnosticState.markUsed(*ObjectKey);
+              }
+
+              if (ParameterSelectorCandidates) {
+                for (api_notes::FunctionObjectSelector ObjectSelector :
+                     ObjectSelectors) {
+                  processExactAPINotes<api_notes::CXXMethodInfo>(
+                      *this, CXXMethod, *ParameterSelectorCandidates,
+                      [&](ArrayRef<std::string> Parameters) {
+                        api_notes::FunctionSelector Selector;
+                        Selector.Parameters.emplace(Parameters.begin(),
+                                                    Parameters.end());
+                        Selector.Object = ObjectSelector;
+                        return Reader->lookupCXXMethod(Context->id, MethodName,
+                                                       Selector);
+                      });
+                  DiagnosticState.markCandidatesUsed(
+                      [&](ArrayRef<std::string> Parameters) {
+                        api_notes::FunctionSelector Selector;
+                        Selector.Parameters.emplace(Parameters.begin(),
+                                                    Parameters.end());
+                        Selector.Object = ObjectSelector;
+                        return Reader->getCXXMethodSelectorKey(
+                            Context->id, MethodName, Selector);
+                      },
+                      *ParameterSelectorCandidates);
+                }
+              }
+            }
           }
         }
       }
@@ -1452,20 +1550,27 @@ void 
APINotesSelectorDiagnosticReaderState::diagnoseUnused(
     if (Selector.second)
       continue;
 
-    auto SeenName =
-        SeenNames.find(Selector.first.getWithoutParameterSelector());
+    auto SeenName = SeenNames.find(Selector.first.getNameOnlyKey());
     if (SeenName == SeenNames.end())
       continue;
 
-    std::optional<SmallVector<std::string, 4>> ParameterSpellings =
-        Reader.getParameterSelectorSpellingsForDiagnostics(Selector.first);
-    if (!ParameterSpellings)
-      continue;
+    std::optional<SmallVector<std::string, 4>> ParameterSpellings;
+    if (Selector.first.Key.parameterTypeIDs) {
+      ParameterSpellings =
+          Reader.getParameterSelectorSpellingsForDiagnostics(Selector.first);
+      if (!ParameterSpellings)
+        continue;
+    }
+
+    std::optional<ArrayRef<std::string>> ParameterRefs;
+    if (ParameterSpellings)
+      ParameterRefs = ArrayRef<std::string>(*ParameterSpellings);
 
     S.Diag(SeenName->second.Loc, diag::warn_apinotes_message)
         << (llvm::Twine("API notes entry for '") + SeenName->second.Name +
-            "' has unmatched Where.Parameters " +
-            api_notes::formatAPINotesParameterSelector(*ParameterSpellings))
+            "' has unmatched " +
+            api_notes::formatAPINotesFunctionSelector(
+                ParameterRefs, Selector.first.Key.objectSelector))
                .str();
   }
 }
diff --git a/clang/lib/Sema/SemaAPINotesInternal.h 
b/clang/lib/Sema/SemaAPINotesInternal.h
index 5766343956ce5..b09968e166243 100644
--- a/clang/lib/Sema/SemaAPINotesInternal.h
+++ b/clang/lib/Sema/SemaAPINotesInternal.h
@@ -39,11 +39,11 @@ struct APINotesSelectorDiagnosticName {
 /// end-of-TU diagnostics can warn about exact selectors for known names that
 /// were never matched.
 struct APINotesSelectorDiagnosticReaderState {
-  /// Exact Where.Parameters selector keys stored by API notes. The bool is
-  /// true once Sema sees a declaration matching the exact selector.
+  /// Function selector keys stored by API notes. The bool is true once
+  /// Sema sees a declaration matching the selector.
   llvm::DenseMap<api_notes::APINotesFunctionSelectorKey, bool> SelectorUsed;
 
-  /// Maps broad/name-only keys to a declaration location/name used for
+  /// Maps broad name-only keys to a declaration location/name used for
   /// diagnostics.
   llvm::DenseMap<api_notes::APINotesFunctionSelectorKey,
                  APINotesSelectorDiagnosticName>
@@ -63,7 +63,7 @@ struct APINotesSelectorDiagnosticReaderState {
 
   void noteSeenDeclaration(const api_notes::APINotesFunctionSelectorKey &Key,
                            llvm::StringRef Name, SourceLocation Loc) {
-    SeenNames.insert({Key.getWithoutParameterSelector(), {Loc, Name.str()}});
+    SeenNames.insert({Key.getNameOnlyKey(), {Loc, Name.str()}});
   }
 
   void markUsed(const api_notes::APINotesFunctionSelectorKey &Key) {
diff --git a/clang/test/APINotes/Inputs/Headers/WhereObjectQualifiers.apinotes 
b/clang/test/APINotes/Inputs/Headers/WhereObjectQualifiers.apinotes
new file mode 100644
index 0000000000000..5397d46fbd883
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/WhereObjectQualifiers.apinotes
@@ -0,0 +1,96 @@
+---
+Name: WhereObjectQualifiers
+Tags:
+- Name: ObjectBuilder
+  Methods:
+  - Name: buildRef
+    Where:
+      Object:
+        Ref: lvalue
+    SwiftName: buildFromLValue()
+  - Name: buildRef
+    Where:
+      Parameters: []
+      Object:
+        Ref: rvalue
+    SwiftName: buildFromRValue()
+  - Name: buildConst
+    Where:
+      Parameters: []
+      Object:
+        Const: false
+        Ref: lvalue
+    SwiftName: buildMutableLValue()
+  - Name: buildConst
+    Where:
+      Parameters: []
+      Object:
+        Const: true
+        Ref: lvalue
+    SwiftName: buildConstLValue()
+  - Name: buildVolatile
+    Where:
+      Parameters: []
+      Object:
+        Volatile: false
+    SwiftName: buildNonVolatile()
+  - Name: buildVolatile
+    Where:
+      Parameters: []
+      Object:
+        Volatile: true
+    SwiftName: buildVolatile()
+  - Name: buildNone
+    Where:
+      Parameters: []
+      Object:
+        Ref: none
+    SwiftName: buildUnqualified()
+  - Name: buildCombined
+    Where:
+      Parameters: []
+      Object:
+        Const: true
+        Volatile: true
+        Ref: lvalue
+    SwiftName: buildConstVolatileLValue()
+  - Name: buildConstRValue
+    Where:
+      Parameters: []
+      Object:
+        Const: true
+        Ref: rvalue
+    SwiftName: buildConstRValue()
+  - Name: buildVolatileRValue
+    Where:
+      Parameters: []
+      Object:
+        Volatile: true
+        Ref: rvalue
+    SwiftName: buildVolatileRValue()
+  - Name: buildObjectOnly
+    Where:
+      Object:
+        Ref: lvalue
+    SwiftName: buildObjectOnlyLValue(_:)
+  - Name: buildStatic
+    Where:
+      Parameters: []
+      Object:
+        Ref: none
+    SwiftName: shouldNotApplyToStatic()
+  - Name: buildStaticObjectOnly
+    Where:
+      Object:
+        Ref: none
+    SwiftName: shouldNotApplyToStaticObjectOnly()
+  - Name: consume
+    Where:
+      Parameters:
+      - 'ObjectBuffer &'
+    SwiftName: consumeBorrowed(_:)
+  - Name: consume
+    Where:
+      Parameters:
+      - 'ObjectBuffer &&'
+    SwiftName: consumeOwned(_:)
diff --git a/clang/test/APINotes/Inputs/Headers/WhereObjectQualifiers.h 
b/clang/test/APINotes/Inputs/Headers/WhereObjectQualifiers.h
new file mode 100644
index 0000000000000..ed3c5ed92e8e1
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/WhereObjectQualifiers.h
@@ -0,0 +1,30 @@
+#ifndef WHERE_OBJECT_QUALIFIERS_H
+#define WHERE_OBJECT_QUALIFIERS_H
+
+struct ObjectBuffer {};
+
+struct ObjectBuilder {
+  void buildRef() &;
+  void buildRef() &&;
+
+  void buildConst() &;
+  void buildConst() const &;
+
+  void buildVolatile();
+  void buildVolatile() volatile;
+
+  void buildNone();
+  void buildCombined() const volatile &;
+  void buildConstRValue() const &&;
+  void buildVolatileRValue() volatile &&;
+  void buildObjectOnly(int) &;
+  void buildObjectOnly(double) &;
+  void buildObjectOnly(int) &&;
+  static void buildStatic();
+  static void buildStaticObjectOnly();
+
+  void consume(ObjectBuffer &);
+  void consume(ObjectBuffer &&);
+};
+
+#endif // WHERE_OBJECT_QUALIFIERS_H
diff --git a/clang/test/APINotes/Inputs/Headers/module.modulemap 
b/clang/test/APINotes/Inputs/Headers/module.modulemap
index 592d482ea7a57..602e44273ff60 100644
--- a/clang/test/APINotes/Inputs/Headers/module.modulemap
+++ b/clang/test/APINotes/Inputs/Headers/module.modulemap
@@ -75,3 +75,8 @@ module WhereParametersSema {
   header "WhereParametersSema.h"
   export *
 }
+
+module WhereObjectQualifiers {
+  header "WhereObjectQualifiers.h"
+  export *
+}
diff --git 
a/clang/test/APINotes/Inputs/WhereObjectQualifiersDiag/APINotes.apinotes 
b/clang/test/APINotes/Inputs/WhereObjectQualifiersDiag/APINotes.apinotes
new file mode 100644
index 0000000000000..3a6a39c17d9c8
--- /dev/null
+++ b/clang/test/APINotes/Inputs/WhereObjectQualifiersDiag/APINotes.apinotes
@@ -0,0 +1,46 @@
+---
+Name: WhereObjectQualifiers
+Functions:
+- Name: invalidGlobal
+  Where:
+    Parameters: []
+    Object:
+      Ref: none
+  SwiftName: invalidGlobal()
+Tags:
+- Name: ObjectDiagBuilder
+  Methods:
+  - Name: objectOnly
+    Where:
+      Object:
+        Ref: none
+    SwiftName: objectOnly()
+  - Name: emptyObject
+    Where:
+      Parameters: []
+      Object: {}
+    SwiftName: emptyObject()
+  - Name: duplicate
+    Where:
+      Parameters: []
+      Object:
+        Ref: lvalue
+    SwiftName: duplicateOne()
+  - Name: duplicate
+    Where:
+      Parameters: []
+      Object:
+        Ref: lvalue
+    SwiftName: duplicateTwo()
+  - Name: acceptedDifferentRef
+    Where:
+      Parameters: []
+      Object:
+        Ref: lvalue
+    SwiftName: acceptedLValue()
+  - Name: acceptedDifferentRef
+    Where:
+      Parameters: []
+      Object:
+        Ref: rvalue
+    SwiftName: acceptedRValue()
diff --git 
a/clang/test/APINotes/Inputs/WhereObjectQualifiersDiag/WhereObjectQualifiers.h 
b/clang/test/APINotes/Inputs/WhereObjectQualifiersDiag/WhereObjectQualifiers.h
new file mode 100644
index 0000000000000..6748c36ceb23c
--- /dev/null
+++ 
b/clang/test/APINotes/Inputs/WhereObjectQualifiersDiag/WhereObjectQualifiers.h
@@ -0,0 +1,14 @@
+#ifndef WHERE_OBJECT_QUALIFIERS_DIAG_H
+#define WHERE_OBJECT_QUALIFIERS_DIAG_H
+
+void invalidGlobal();
+
+struct ObjectDiagBuilder {
+  void objectOnly();
+  void emptyObject();
+  void duplicate();
+  void acceptedDifferentRef() &;
+  void acceptedDifferentRef() &&;
+};
+
+#endif // WHERE_OBJECT_QUALIFIERS_DIAG_H
diff --git a/clang/test/APINotes/where-object-qualifiers.cpp 
b/clang/test/APINotes/where-object-qualifiers.cpp
new file mode 100644
index 0000000000000..78eff1d56e3cd
--- /dev/null
+++ b/clang/test/APINotes/where-object-qualifiers.cpp
@@ -0,0 +1,63 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -fsyntax-only -I 
%S/Inputs/Headers %s -x c++
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -I %S/Inputs/Headers %s 
-ast-dump -ast-dump-filter ObjectBuilder::buildRef -x c++ | FileCheck 
--check-prefix=REF %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -I %S/Inputs/Headers %s 
-ast-dump -ast-dump-filter ObjectBuilder::buildConst -x c++ | FileCheck 
--check-prefix=CONST %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -I %S/Inputs/Headers %s 
-ast-dump -ast-dump-filter ObjectBuilder::buildVolatile -x c++ | FileCheck 
--check-prefix=VOLATILE %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -I %S/Inputs/Headers %s 
-ast-dump -ast-dump-filter ObjectBuilder::buildNone -x c++ | FileCheck 
--check-prefix=NONE %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -I %S/Inputs/Headers %s 
-ast-dump -ast-dump-filter ObjectBuilder::buildCombined -x c++ | FileCheck 
--check-prefix=COMBINED-CVREF %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -I %S/Inputs/Headers %s 
-ast-dump -ast-dump-filter ObjectBuilder::buildConstRValue -x c++ | FileCheck 
--check-prefix=COMBINED-CONST-RVALUE %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -I %S/Inputs/Headers %s 
-ast-dump -ast-dump-filter ObjectBuilder::buildVolatileRValue -x c++ | 
FileCheck --check-prefix=COMBINED-VOLATILE-RVALUE %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -I %S/Inputs/Headers %s 
-ast-dump -ast-dump-filter ObjectBuilder::buildObjectOnly -x c++ | FileCheck 
--check-prefix=OBJECT-ONLY %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -I %S/Inputs/Headers %s 
-ast-dump -ast-dump-filter ObjectBuilder::buildStatic -x c++ | FileCheck 
--check-prefix=STATIC %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiers 
-fdisable-module-hash -fapinotes-modules -Wno-apinotes -I %S/Inputs/Headers %s 
-ast-dump -ast-dump-filter ObjectBuilder::consume -x c++ | FileCheck 
--check-prefix=PARAM-REF %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereObjectQualifiersWarnings 
-fdisable-module-hash -fapinotes-modules -Wapinotes -fsyntax-only -I 
%S/Inputs/Headers %s -x c++ 2>&1 | FileCheck --check-prefix=UNMATCHED %s
+// RUN: not %clang_cc1 -fsyntax-only -fapinotes %s -I 
%S/Inputs/WhereObjectQualifiersDiag 2>&1 | FileCheck --check-prefix=DIAG %s
+
+#include "WhereObjectQualifiers.h"
+
+// REF: CXXMethodDecl {{.+}} buildRef 'void () &{{.*}}'
+// REF: SwiftNameAttr {{.+}} "buildFromLValue()"
+// REF: CXXMethodDecl {{.+}} buildRef 'void () &&{{.*}}'
+// REF: SwiftNameAttr {{.+}} "buildFromRValue()"
+
+// CONST: CXXMethodDecl {{.+}} buildConst 'void () &{{.*}}'
+// CONST: SwiftNameAttr {{.+}} "buildMutableLValue()"
+// CONST: CXXMethodDecl {{.+}} buildConst 'void () const &{{.*}}'
+// CONST: SwiftNameAttr {{.+}} "buildConstLValue()"
+
+// VOLATILE: CXXMethodDecl {{.+}} buildVolatile 'void (){{.*}}'
+// VOLATILE: SwiftNameAttr {{.+}} "buildNonVolatile()"
+// VOLATILE: CXXMethodDecl {{.+}} buildVolatile 'void () volatile{{.*}}'
+// VOLATILE: SwiftNameAttr {{.+}} "buildVolatile()"
+
+// NONE: CXXMethodDecl {{.+}} buildNone 'void (){{.*}}'
+// NONE: SwiftNameAttr {{.+}} "buildUnqualified()"
+
+// COMBINED-CVREF: CXXMethodDecl {{.+}} buildCombined 'void () const volatile 
&{{.*}}'
+// COMBINED-CVREF: SwiftNameAttr {{.+}} "buildConstVolatileLValue()"
+// COMBINED-CONST-RVALUE: CXXMethodDecl {{.+}} buildConstRValue 'void () const 
&&{{.*}}'
+// COMBINED-CONST-RVALUE: SwiftNameAttr {{.+}} "buildConstRValue()"
+// COMBINED-VOLATILE-RVALUE: CXXMethodDecl {{.+}} buildVolatileRValue 'void () 
volatile &&{{.*}}'
+// COMBINED-VOLATILE-RVALUE: SwiftNameAttr {{.+}} "buildVolatileRValue()"
+
+// OBJECT-ONLY: CXXMethodDecl {{.+}} buildObjectOnly 'void (int) &{{.*}}'
+// OBJECT-ONLY: SwiftNameAttr {{.+}} "buildObjectOnlyLValue(_:)"
+// OBJECT-ONLY: CXXMethodDecl {{.+}} buildObjectOnly 'void (double) &{{.*}}'
+// OBJECT-ONLY: SwiftNameAttr {{.+}} "buildObjectOnlyLValue(_:)"
+// OBJECT-ONLY: CXXMethodDecl {{.+}} buildObjectOnly 'void (int) &&{{.*}}'
+// OBJECT-ONLY-NOT: SwiftNameAttr
+
+// STATIC: CXXMethodDecl {{.+}} buildStatic 'void ()' static
+// STATIC-NOT: SwiftNameAttr
+
+// UNMATCHED-DAG: warning: API notes entry for 'buildStatic' has unmatched 
Where.Parameters [] Object{Ref: none}
+// UNMATCHED-DAG: warning: API notes entry for 'buildStaticObjectOnly' has 
unmatched Where.Object Object{Ref: none}
+
+// PARAM-REF: CXXMethodDecl {{.+}} consume 'void (ObjectBuffer &)'
+// PARAM-REF: SwiftNameAttr {{.+}} "consumeBorrowed(_:)"
+// PARAM-REF: CXXMethodDecl {{.+}} consume 'void (ObjectBuffer &&)'
+// PARAM-REF: SwiftNameAttr {{.+}} "consumeOwned(_:)"
+
+// DIAG-DAG: error: 'Object' is only supported on C++ methods
+// DIAG-DAG: error: 'Object' requires at least one field
+// DIAG-DAG: error: multiple API notes entries for C++ method 'duplicate' with 
Where.Parameters [] Object{Ref: lvalue}

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

Reply via email to