[clang] [APINotes] Support annotating C++ methods (PR #99512)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 18 08:23:16 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Egor Zhdan (egorzhdan)
<details>
<summary>Changes</summary>
This adds support for adding Clang attributes to C++ methods declared within C++ records by using API Notes.
For instance:
```
Tags:
- Name: IntWrapper
Methods:
- Name: getIncremented
Availability: none
```
This is the first instance of something within a C++ record being annotated with API Notes, so it adds the necessary infra to make a C++ record an "API Notes context".
Notably this does not add support for nested C++ tags. That will be added in a follow-up patch.
rdar://131387880
---
Patch is 33.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/99512.diff
15 Files Affected:
- (modified) clang/include/clang/APINotes/APINotesReader.h (+21)
- (modified) clang/include/clang/APINotes/APINotesWriter.h (+8)
- (modified) clang/include/clang/APINotes/Types.h (+7)
- (modified) clang/lib/APINotes/APINotesFormat.h (+29)
- (modified) clang/lib/APINotes/APINotesReader.cpp (+149)
- (modified) clang/lib/APINotes/APINotesWriter.cpp (+72)
- (modified) clang/lib/APINotes/APINotesYAMLCompiler.cpp (+94-70)
- (modified) clang/lib/Sema/SemaAPINotes.cpp (+41-9)
- (added) clang/test/APINotes/Inputs/Headers/Methods.apinotes (+8)
- (added) clang/test/APINotes/Inputs/Headers/Methods.h (+14)
- (modified) clang/test/APINotes/Inputs/Headers/Namespaces.apinotes (+3)
- (modified) clang/test/APINotes/Inputs/Headers/Namespaces.h (+1)
- (modified) clang/test/APINotes/Inputs/Headers/module.modulemap (+4)
- (added) clang/test/APINotes/methods.cpp (+9)
- (modified) clang/test/APINotes/namespaces.cpp (+5)
``````````diff
diff --git a/clang/include/clang/APINotes/APINotesReader.h b/clang/include/clang/APINotes/APINotesReader.h
index 37a4ff7a69712..03657352c49a5 100644
--- a/clang/include/clang/APINotes/APINotesReader.h
+++ b/clang/include/clang/APINotes/APINotesReader.h
@@ -141,6 +141,16 @@ class APINotesReader {
ObjCSelectorRef Selector,
bool IsInstanceMethod);
+ /// Look for information regarding the given C++ method in the given C++ tag
+ /// context.
+ ///
+ /// \param CtxID The ID that references the parent context, i.e. a C++ tag.
+ /// \param Name The name of the C++ method we're looking for.
+ ///
+ /// \returns Information about the method, if known.
+ VersionedInfo<CXXMethodInfo> lookupCXXMethod(ContextID CtxID,
+ llvm::StringRef Name);
+
/// Look for information regarding the given global variable.
///
/// \param Name The name of the global variable.
@@ -166,6 +176,17 @@ class APINotesReader {
/// \returns information about the enumerator, if known.
VersionedInfo<EnumConstantInfo> lookupEnumConstant(llvm::StringRef Name);
+ /// Look for the context ID of the given C++ tag.
+ ///
+ /// \param Name The name of the tag we're looking for.
+ /// \param ParentCtx The context in which this tag is declared, e.g. a C++
+ /// namespace.
+ ///
+ /// \returns The ID, if known.
+ std::optional<ContextID>
+ lookupTagID(llvm::StringRef Name,
+ std::optional<Context> ParentCtx = std::nullopt);
+
/// Look for information regarding the given tag
/// (struct/union/enum/C++ class).
///
diff --git a/clang/include/clang/APINotes/APINotesWriter.h b/clang/include/clang/APINotes/APINotesWriter.h
index e82dbc7c9540e..e0fe5eacef725 100644
--- a/clang/include/clang/APINotes/APINotesWriter.h
+++ b/clang/include/clang/APINotes/APINotesWriter.h
@@ -78,6 +78,14 @@ class APINotesWriter {
bool IsInstanceMethod, const ObjCMethodInfo &Info,
llvm::VersionTuple SwiftVersion);
+ /// Add information about a specific C++ method.
+ ///
+ /// \param CtxID The context in which this method resides, i.e. a C++ tag.
+ /// \param Name The name of the method.
+ /// \param Info Information about this method.
+ void addCXXMethod(ContextID CtxID, llvm::StringRef Name,
+ const CXXMethodInfo &Info, llvm::VersionTuple SwiftVersion);
+
/// Add information about a global variable.
///
/// \param Name The name of this global variable.
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index b389aa8d56f16..c8e5e4df25d17 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -656,6 +656,12 @@ class GlobalFunctionInfo : public FunctionInfo {
GlobalFunctionInfo() {}
};
+/// Describes API notes data for a C++ method.
+class CXXMethodInfo : public FunctionInfo {
+public:
+ CXXMethodInfo() {}
+};
+
/// Describes API notes data for an enumerator.
class EnumConstantInfo : public CommonEntityInfo {
public:
@@ -789,6 +795,7 @@ enum class ContextKind : uint8_t {
ObjCClass = 0,
ObjCProtocol = 1,
Namespace = 2,
+ Tag = 3,
};
struct Context {
diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h
index 42dfe7a773a97..cd6456dbe37b2 100644
--- a/clang/lib/APINotes/APINotesFormat.h
+++ b/clang/lib/APINotes/APINotesFormat.h
@@ -63,6 +63,10 @@ enum BlockID {
/// about the method.
OBJC_METHOD_BLOCK_ID,
+ /// The C++ method data block, which maps C++ (context id, method name) pairs
+ /// to information about the method.
+ CXX_METHOD_BLOCK_ID,
+
/// The Objective-C selector data block, which maps Objective-C
/// selector names (# of pieces, identifier IDs) to the selector ID
/// used in other tables.
@@ -181,6 +185,20 @@ using ObjCMethodDataLayout =
>;
} // namespace objc_method_block
+namespace cxx_method_block {
+enum {
+ CXX_METHOD_DATA = 1,
+};
+
+using CXXMethodDataLayout =
+ llvm::BCRecordLayout<CXX_METHOD_DATA, // record ID
+ llvm::BCVBR<16>, // table offset within the blob (see
+ // below)
+ llvm::BCBlob // map from C++ (context id, name)
+ // tuples to C++ method information
+ >;
+} // namespace cxx_method_block
+
namespace objc_selector_block {
enum {
OBJC_SELECTOR_DATA = 1,
@@ -269,6 +287,17 @@ struct ContextTableKey {
: parentContextID(parentContextID), contextKind(contextKind),
contextID(contextID) {}
+ ContextTableKey(std::optional<ContextID> ParentContextID, ContextKind Kind,
+ uint32_t ContextID)
+ : parentContextID(ParentContextID ? ParentContextID->Value : -1),
+ contextKind(static_cast<uint8_t>(Kind)), contextID(ContextID) {}
+
+ ContextTableKey(std::optional<Context> ParentContext, ContextKind Kind,
+ uint32_t ContextID)
+ : ContextTableKey(ParentContext ? std::make_optional(ParentContext->id)
+ : std::nullopt,
+ Kind, ContextID) {}
+
llvm::hash_code hashValue() const {
return llvm::hash_value(
std::tuple{parentContextID, contextKind, contextID});
diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp
index 7600738374840..768fdc231bd57 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -473,6 +473,29 @@ class GlobalFunctionTableInfo
}
};
+/// Used to deserialize the on-disk C++ method table.
+class CXXMethodTableInfo
+ : public VersionedTableInfo<CXXMethodTableInfo,
+ SingleDeclTableKey, 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};
+ }
+
+ hash_value_type ComputeHash(internal_key_type Key) {
+ return static_cast<size_t>(Key.hashValue());
+ }
+
+ static CXXMethodInfo readUnversioned(internal_key_type Key,
+ const uint8_t *&Data) {
+ CXXMethodInfo Info;
+ ReadFunctionInfo(Data, Info);
+ return Info;
+ }
+};
+
/// Used to deserialize the on-disk enumerator table.
class EnumConstantTableInfo
: public VersionedTableInfo<EnumConstantTableInfo, uint32_t,
@@ -630,6 +653,12 @@ class APINotesReader::Implementation {
/// The Objective-C method table.
std::unique_ptr<SerializedObjCMethodTable> ObjCMethodTable;
+ using SerializedCXXMethodTable =
+ llvm::OnDiskIterableChainedHashTable<CXXMethodTableInfo>;
+
+ /// The C++ method table.
+ std::unique_ptr<SerializedCXXMethodTable> CXXMethodTable;
+
using SerializedObjCSelectorTable =
llvm::OnDiskIterableChainedHashTable<ObjCSelectorTableInfo>;
@@ -683,6 +712,8 @@ class APINotesReader::Implementation {
llvm::SmallVectorImpl<uint64_t> &Scratch);
bool readObjCMethodBlock(llvm::BitstreamCursor &Cursor,
llvm::SmallVectorImpl<uint64_t> &Scratch);
+ bool readCXXMethodBlock(llvm::BitstreamCursor &Cursor,
+ llvm::SmallVectorImpl<uint64_t> &Scratch);
bool readObjCSelectorBlock(llvm::BitstreamCursor &Cursor,
llvm::SmallVectorImpl<uint64_t> &Scratch);
bool readGlobalVariableBlock(llvm::BitstreamCursor &Cursor,
@@ -1140,6 +1171,81 @@ bool APINotesReader::Implementation::readObjCMethodBlock(
return false;
}
+bool APINotesReader::Implementation::readCXXMethodBlock(
+ llvm::BitstreamCursor &Cursor, llvm::SmallVectorImpl<uint64_t> &Scratch) {
+ if (Cursor.EnterSubBlock(CXX_METHOD_BLOCK_ID))
+ return true;
+
+ llvm::Expected<llvm::BitstreamEntry> MaybeNext = Cursor.advance();
+ if (!MaybeNext) {
+ // FIXME this drops the error on the floor.
+ consumeError(MaybeNext.takeError());
+ return false;
+ }
+ llvm::BitstreamEntry Next = MaybeNext.get();
+ while (Next.Kind != llvm::BitstreamEntry::EndBlock) {
+ if (Next.Kind == llvm::BitstreamEntry::Error)
+ return true;
+
+ if (Next.Kind == llvm::BitstreamEntry::SubBlock) {
+ // Unknown sub-block, possibly for use by a future version of the
+ // API notes format.
+ if (Cursor.SkipBlock())
+ return true;
+
+ MaybeNext = Cursor.advance();
+ if (!MaybeNext) {
+ // FIXME this drops the error on the floor.
+ consumeError(MaybeNext.takeError());
+ return false;
+ }
+ Next = MaybeNext.get();
+ continue;
+ }
+
+ Scratch.clear();
+ llvm::StringRef BlobData;
+ llvm::Expected<unsigned> MaybeKind =
+ Cursor.readRecord(Next.ID, Scratch, &BlobData);
+ if (!MaybeKind) {
+ // FIXME this drops the error on the floor.
+ consumeError(MaybeKind.takeError());
+ return false;
+ }
+ unsigned Kind = MaybeKind.get();
+ switch (Kind) {
+ case cxx_method_block::CXX_METHOD_DATA: {
+ // Already saw C++ method table.
+ if (CXXMethodTable)
+ return true;
+
+ uint32_t tableOffset;
+ cxx_method_block::CXXMethodDataLayout::readRecord(Scratch, tableOffset);
+ auto base = reinterpret_cast<const uint8_t *>(BlobData.data());
+
+ CXXMethodTable.reset(SerializedCXXMethodTable::Create(
+ base + tableOffset, base + sizeof(uint32_t), base));
+ break;
+ }
+
+ default:
+ // Unknown record, possibly for use by a future version of the
+ // module format.
+ break;
+ }
+
+ MaybeNext = Cursor.advance();
+ if (!MaybeNext) {
+ // FIXME this drops the error on the floor.
+ consumeError(MaybeNext.takeError());
+ return false;
+ }
+ Next = MaybeNext.get();
+ }
+
+ return false;
+}
+
bool APINotesReader::Implementation::readObjCSelectorBlock(
llvm::BitstreamCursor &Cursor, llvm::SmallVectorImpl<uint64_t> &Scratch) {
if (Cursor.EnterSubBlock(OBJC_SELECTOR_BLOCK_ID))
@@ -1692,6 +1798,14 @@ APINotesReader::APINotesReader(llvm::MemoryBuffer *InputBuffer,
}
break;
+ case CXX_METHOD_BLOCK_ID:
+ if (!HasValidControlBlock ||
+ Implementation->readCXXMethodBlock(Cursor, Scratch)) {
+ Failed = true;
+ return;
+ }
+ break;
+
case OBJC_SELECTOR_BLOCK_ID:
if (!HasValidControlBlock ||
Implementation->readObjCSelectorBlock(Cursor, Scratch)) {
@@ -1911,6 +2025,23 @@ auto APINotesReader::lookupObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,
return {Implementation->SwiftVersion, *Known};
}
+auto APINotesReader::lookupCXXMethod(ContextID CtxID, llvm::StringRef Name)
+ -> VersionedInfo<CXXMethodInfo> {
+ if (!Implementation->CXXMethodTable)
+ return std::nullopt;
+
+ std::optional<IdentifierID> NameID = Implementation->getIdentifier(Name);
+ if (!NameID)
+ return std::nullopt;
+
+ auto Known = Implementation->CXXMethodTable->find(
+ SingleDeclTableKey(CtxID.Value, *NameID));
+ if (Known == Implementation->CXXMethodTable->end())
+ return std::nullopt;
+
+ return {Implementation->SwiftVersion, *Known};
+}
+
auto APINotesReader::lookupGlobalVariable(llvm::StringRef Name,
std::optional<Context> Ctx)
-> VersionedInfo<GlobalVariableInfo> {
@@ -1965,6 +2096,24 @@ auto APINotesReader::lookupEnumConstant(llvm::StringRef Name)
return {Implementation->SwiftVersion, *Known};
}
+auto APINotesReader::lookupTagID(llvm::StringRef Name,
+ std::optional<Context> ParentCtx)
+ -> std::optional<ContextID> {
+ if (!Implementation->ContextIDTable)
+ return std::nullopt;
+
+ std::optional<IdentifierID> TagID = Implementation->getIdentifier(Name);
+ if (!TagID)
+ return std::nullopt;
+
+ auto KnownID = Implementation->ContextIDTable->find(
+ ContextTableKey(ParentCtx, ContextKind::Tag, *TagID));
+ if (KnownID == Implementation->ContextIDTable->end())
+ return std::nullopt;
+
+ return ContextID(*KnownID);
+}
+
auto APINotesReader::lookupTag(llvm::StringRef Name, std::optional<Context> Ctx)
-> VersionedInfo<TagInfo> {
if (!Implementation->TagTable)
diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp
index 1090d3f20df21..e259c761591ba 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -70,6 +70,13 @@ class APINotesWriter::Implementation {
llvm::SmallVector<std::pair<VersionTuple, ObjCMethodInfo>, 1>>
ObjCMethods;
+ /// Information about C++ methods.
+ ///
+ /// Indexed by the context ID and name ID.
+ llvm::DenseMap<SingleDeclTableKey,
+ llvm::SmallVector<std::pair<VersionTuple, CXXMethodInfo>, 1>>
+ CXXMethods;
+
/// Mapping from selectors to selector ID.
llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;
@@ -150,6 +157,7 @@ class APINotesWriter::Implementation {
void writeContextBlock(llvm::BitstreamWriter &Stream);
void writeObjCPropertyBlock(llvm::BitstreamWriter &Stream);
void writeObjCMethodBlock(llvm::BitstreamWriter &Stream);
+ void writeCXXMethodBlock(llvm::BitstreamWriter &Stream);
void writeObjCSelectorBlock(llvm::BitstreamWriter &Stream);
void writeGlobalVariableBlock(llvm::BitstreamWriter &Stream);
void writeGlobalFunctionBlock(llvm::BitstreamWriter &Stream);
@@ -181,6 +189,7 @@ void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream &OS) {
writeContextBlock(Stream);
writeObjCPropertyBlock(Stream);
writeObjCMethodBlock(Stream);
+ writeCXXMethodBlock(Stream);
writeObjCSelectorBlock(Stream);
writeGlobalVariableBlock(Stream);
writeGlobalFunctionBlock(Stream);
@@ -765,6 +774,34 @@ class ObjCMethodTableInfo
emitFunctionInfo(OS, OMI);
}
};
+
+/// Used to serialize the on-disk C++ method table.
+class CXXMethodTableInfo
+ : public VersionedTableInfo<CXXMethodTableInfo, SingleDeclTableKey,
+ CXXMethodInfo> {
+public:
+ unsigned getKeyLength(key_type_ref) {
+ return sizeof(uint32_t) + sizeof(uint32_t);
+ }
+
+ 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);
+ }
+
+ hash_value_type ComputeHash(key_type_ref key) {
+ return static_cast<size_t>(key.hashValue());
+ }
+
+ unsigned getUnversionedInfoSize(const CXXMethodInfo &OMI) {
+ return getFunctionInfoSize(OMI);
+ }
+
+ void emitUnversionedInfo(raw_ostream &OS, const CXXMethodInfo &OMI) {
+ emitFunctionInfo(OS, OMI);
+ }
+};
} // namespace
void APINotesWriter::Implementation::writeObjCMethodBlock(
@@ -794,6 +831,33 @@ void APINotesWriter::Implementation::writeObjCMethodBlock(
}
}
+void APINotesWriter::Implementation::writeCXXMethodBlock(
+ llvm::BitstreamWriter &Stream) {
+ llvm::BCBlockRAII Scope(Stream, CXX_METHOD_BLOCK_ID, 3);
+
+ if (CXXMethods.empty())
+ return;
+
+ {
+ llvm::SmallString<4096> HashTableBlob;
+ uint32_t Offset;
+ {
+ llvm::OnDiskChainedHashTableGenerator<CXXMethodTableInfo> Generator;
+ for (auto &OM : CXXMethods)
+ Generator.insert(OM.first, OM.second);
+
+ llvm::raw_svector_ostream BlobStream(HashTableBlob);
+ // Make sure that no bucket is at offset 0
+ llvm::support::endian::write<uint32_t>(BlobStream, 0,
+ llvm::endianness::little);
+ Offset = Generator.Emit(BlobStream);
+ }
+
+ cxx_method_block::CXXMethodDataLayout CXXMethodData(Stream);
+ CXXMethodData.emit(Scratch, Offset, HashTableBlob);
+ }
+}
+
namespace {
/// Used to serialize the on-disk Objective-C selector table.
class ObjCSelectorTableInfo {
@@ -1344,6 +1408,14 @@ 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);
+ Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
+}
+
void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
llvm::StringRef Name,
const GlobalVariableInfo &Info,
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index 870b64e3b7a9b..060e1fdaf2fd9 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -420,6 +420,7 @@ struct Tag {
std::optional<bool> FlagEnum;
std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
std::optional<bool> SwiftCopyable;
+ FunctionsSeq Methods;
};
typedef std::vector<Tag> TagsSeq;
@@ -454,6 +455,7 @@ template <> struct MappingTraits<Tag> {
IO.mapOptional("FlagEnum", T.FlagEnum);
IO.mapOptional("EnumKind", T.EnumConvenienceKind);
IO.mapOptional("SwiftCopyable", T.SwiftCopyable);
+ IO.mapOptional("Methods", T.Methods);
}
};
} // namespace yaml
@@ -874,6 +876,96 @@ class YAMLConverter {
TheNamespace.Items, SwiftVersion);
}
+ void convertFunction(const Function &Function, FunctionInfo &FI) {
+ convertAvailability(Function.Availability, FI, Function.Name);
+ FI.setSwiftPrivate(Function.SwiftPrivate);
+ FI.SwiftName = std::string(Function.SwiftName);
+ convertParams(Function.Params, FI);
+ convertNullability(Function.Nullability, Function.NullabilityOfRet, FI,
+ Function.Name);
+ FI.ResultType = std::string(Function.ResultType);
+ FI.setRetainCountConvention(Function.RetainCountConvention);
+ }
+
+ void convertTagContext(std::optional<Context> ParentContext, const Tag &T,
+ VersionTuple SwiftVersion) {
+ TagInfo TI;
+ std::optional<ContextID> ParentContextID =
+ ParentContext ? std::optional<ContextID>(ParentContext->id)
+ : std::nullopt;
+ convertCommonType(T, TI, T.Name);
+
+ if ((T.SwiftRetainOp || T.SwiftReleaseOp) && !T.SwiftImportAs) {
+ emitError(llvm::Twine("should declare SwiftImportAs to use "
+ "SwiftRetainOp and SwiftReleaseOp (for ") +
+ T.Name + ")");
+ return;
+ }
+ if (T.SwiftReleaseOp.has_value() != T.SwiftRetainOp.has_value()) {
+ emitError(llvm::Twine("should declare both SwiftReleaseOp and "
+ "SwiftRetainOp (for ") +
+ T.Name + ")");
+ return;
+ }
+
+ if (T.SwiftImportAs)
+ TI.SwiftImportAs = T.SwiftImportAs;
+ if (T.SwiftRetainOp)
+ TI.SwiftRetainOp = T.SwiftRetainOp;
+ if (T.SwiftReleaseOp)
+ TI.SwiftReleaseOp = T.SwiftReleaseOp;
+
+ if (T.SwiftCopyable)
+ TI.setSwiftCopyable(T.SwiftCopyable);
+
+ if (T.EnumConvenienceKind) {
+ if (T.EnumExtensibility) {
+ emitError(
+ llvm::Twine("cannot mix EnumKind and EnumExtensibility (for ") +
+ T.Name + ")");
+ return;
+ }
+ if (T.FlagEnum) {
+ emitError(llvm::Twine("cannot mix EnumKind and FlagEnum (for ") +
+ T.Name + ")");
+ return;
+ }
+ switch (*T.EnumConvenienceKind) {
+ case EnumConvenienceAliasKind::None:
+ TI.EnumExtensibility = EnumExtensibilityKind::None;
+ TI.setFlagEnum(false);
+ break;
+ case EnumConvenienceAliasKind::CFEnum:
+ TI.EnumExtensibility = EnumExtensibilityKind::Open;
+ TI.setFlagEnum(false);
+ break;
+ case EnumConvenienceAliasKind::CFOptions:
+ TI.EnumExtensibility = EnumExtensibilityKind::Open;
+ TI.setFlagEnum(true);
+ break;
+ case EnumConvenienceAliasKind::CFClosedEnum:
+ TI.EnumExtensibility = EnumExtensibilityKind::Closed;
+ TI.setFlagEnum(false);
+ break;
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/99512
More information about the cfe-commits
mailing list