https://github.com/StoeckOverflow updated https://github.com/llvm/llvm-project/pull/205307
>From 9a0d376597fe0ce04f5af1350ecced91679af5dd Mon Sep 17 00:00:00 2001 From: stoeckoverflow <[email protected]> Date: Tue, 16 Jun 2026 14:08:09 +0200 Subject: [PATCH 1/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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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(_:)" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
