[clang] [APINotes] Match function-like Where.Parameters in Sema (PR #205307)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 29 23:49:36 PDT 2026
https://github.com/StoeckOverflow updated https://github.com/llvm/llvm-project/pull/205307
>From 9a0d376597fe0ce04f5af1350ecced91679af5dd Mon Sep 17 00:00:00 2001
From: stoeckoverflow <dominic-st at gmx.de>
Date: Tue, 16 Jun 2026 14:08:09 +0200
Subject: [PATCH 1/4] [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 <dominic-st at gmx.de>
Date: Fri, 19 Jun 2026 10:47:20 +0200
Subject: [PATCH 2/4] [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 6a7a89a2dacaa16b3f22b240b2d07cacc4fc7561 Mon Sep 17 00:00:00 2001
From: stoeckoverflow <dominic-st at gmx.de>
Date: Mon, 29 Jun 2026 09:28:07 +0200
Subject: [PATCH 3/4] [APINotes] Address Where.Parameters review cleanup
---
clang/lib/APINotes/APINotesWriter.cpp | 4 +--
clang/lib/APINotes/APINotesYAMLCompiler.cpp | 36 +++++++++------------
2 files changed, 17 insertions(+), 23 deletions(-)
diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp
index 0aa9812693386..86fee93ec4765 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -423,9 +423,7 @@ 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.
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index 8e947711dec2f..1c3a59873db25 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -1043,20 +1043,16 @@ class YAMLConverter {
TheNamespace.Items, SwiftVersion);
}
- bool getWhereParameters(
- const Function &Function,
- std::optional<llvm::ArrayRef<llvm::StringRef>> &WhereParameters) {
- WhereParameters = std::nullopt;
+ std::pair<bool, std::optional<llvm::ArrayRef<llvm::StringRef>>>
+ getWhereParameters(const Function &Function) {
if (!Function.Where)
- return true;
+ return {true, std::nullopt};
if (!Function.Where->Parameters) {
emitError("'Where' requires 'Parameters'");
- return false;
+ return {false, std::nullopt};
}
- WhereParameters =
- llvm::ArrayRef<llvm::StringRef>(*Function.Where->Parameters);
- return true;
+ return {true, llvm::ArrayRef<llvm::StringRef>(*Function.Where->Parameters)};
}
template <typename FuncOrMethodInfo>
@@ -1167,15 +1163,15 @@ class YAMLConverter {
}
for (const auto &CXXMethod : T.Methods) {
- std::optional<llvm::ArrayRef<llvm::StringRef>> WhereParameters;
- if (!getWhereParameters(CXXMethod, WhereParameters))
+ auto WhereParameters = getWhereParameters(CXXMethod);
+ if (!WhereParameters.first)
continue;
CXXMethodInfo MI;
convertFunction(CXXMethod, MI);
- if (WhereParameters)
- Writer.addCXXMethod(TagCtxID, CXXMethod.Name, *WhereParameters, MI,
- SwiftVersion);
+ if (WhereParameters.second)
+ Writer.addCXXMethod(TagCtxID, CXXMethod.Name, *WhereParameters.second,
+ MI, SwiftVersion);
else
Writer.addCXXMethod(TagCtxID, CXXMethod.Name, MI, SwiftVersion);
}
@@ -1248,13 +1244,13 @@ class YAMLConverter {
// Write all global functions.
llvm::StringSet<> KnownNameOnlyFunctions;
for (const auto &Function : TLItems.Functions) {
- std::optional<llvm::ArrayRef<llvm::StringRef>> WhereParameters;
- if (!getWhereParameters(Function, WhereParameters))
+ auto WhereParameters = getWhereParameters(Function);
+ if (!WhereParameters.first)
continue;
// Check for duplicate name-only global functions. Selector-aware
// duplicate diagnostics are handled by a later overload-matching PR.
- if (!WhereParameters &&
+ if (!WhereParameters.second &&
!KnownNameOnlyFunctions.insert(Function.Name).second) {
emitError(llvm::Twine("multiple definitions of global function '") +
Function.Name + "'");
@@ -1263,9 +1259,9 @@ class YAMLConverter {
GlobalFunctionInfo GFI;
convertFunction(Function, GFI);
- if (WhereParameters)
- Writer.addGlobalFunction(Ctx, Function.Name, *WhereParameters, GFI,
- SwiftVersion);
+ if (WhereParameters.second)
+ Writer.addGlobalFunction(Ctx, Function.Name, *WhereParameters.second,
+ GFI, SwiftVersion);
else
Writer.addGlobalFunction(Ctx, Function.Name, GFI, SwiftVersion);
}
>From d102ee0ba248ef076a1b120a37ca1ae4176a9ba2 Mon Sep 17 00:00:00 2001
From: stoeckoverflow <dominic-st at gmx.de>
Date: Fri, 19 Jun 2026 11:17:22 +0200
Subject: [PATCH 4/4] [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(_:)"
More information about the cfe-commits
mailing list