Skip to content

[🍒][apinotes][cxx-interop] Add support for namespaces, nested tags, and methods. #5021

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/include/clang/APINotes/APINotesReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ class APINotesReader {
/// \returns information about the global function, if known.
VersionedInfo<GlobalFunctionInfo> lookupGlobalFunction(llvm::StringRef name);

VersionedInfo<GlobalFunctionInfo> lookupMemberFunction(llvm::StringRef name);

/// Look for information regarding the given enumerator.
///
/// \param name The name of the enumerator.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/APINotes/APINotesWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ class APINotesWriter {
void addGlobalFunction(llvm::StringRef name, const GlobalFunctionInfo &info,
llvm::VersionTuple swiftVersion);

void addMemberFunction(llvm::StringRef name, const FunctionInfo &info,
llvm::VersionTuple swiftVersion);

/// Add information about an enumerator.
///
/// \param name The name of this enumerator.
Expand Down
18 changes: 17 additions & 1 deletion clang/include/clang/APINotes/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,8 @@ class FunctionInfo : public CommonEntityInfo {
/// The function parameters.
std::vector<ParamInfo> Params;

llvm::Optional<std::string> SwiftImportAs;

FunctionInfo()
: CommonEntityInfo(), NullabilityAudited(false), NumAdjustedNullable(0),
RawRetainCountConvention() {}
Expand Down Expand Up @@ -665,6 +667,10 @@ class TagInfo : public CommonTypeInfo {
public:
llvm::Optional<EnumExtensibilityKind> EnumExtensibility;

llvm::Optional<std::string> SwiftImportAs;
llvm::Optional<std::string> SwiftRetainOp;
llvm::Optional<std::string> SwiftReleaseOp;

TagInfo() : CommonTypeInfo(), HasFlagEnum(0), IsFlagEnum(0) {}

llvm::Optional<bool> isFlagEnum() const {
Expand All @@ -686,6 +692,13 @@ class TagInfo : public CommonTypeInfo {
if (!EnumExtensibility.hasValue())
EnumExtensibility = RHS.EnumExtensibility;

if (!SwiftImportAs)
SwiftImportAs = RHS.SwiftImportAs;
if (!SwiftRetainOp)
SwiftImportAs = RHS.SwiftRetainOp;
if (!SwiftReleaseOp)
SwiftImportAs = RHS.SwiftReleaseOp;

return *this;
}

Expand All @@ -697,7 +710,10 @@ class TagInfo : public CommonTypeInfo {
inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
return static_cast<const CommonTypeInfo &>(LHS) == RHS &&
LHS.isFlagEnum() == RHS.isFlagEnum() &&
LHS.EnumExtensibility == RHS.EnumExtensibility;
LHS.EnumExtensibility == RHS.EnumExtensibility &&
LHS.SwiftImportAs == RHS.SwiftImportAs &&
LHS.SwiftRetainOp == RHS.SwiftRetainOp &&
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp;
}

inline bool operator!=(const TagInfo &LHS, const TagInfo &RHS) {
Expand Down
16 changes: 15 additions & 1 deletion clang/lib/APINotes/APINotesFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ 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 = 24; // EnumExtensibility + FlagEnum
const uint16_t VERSION_MINOR = 25; // Member functions

using IdentifierID = llvm::PointerEmbeddedInt<unsigned, 31>;
using IdentifierIDField = llvm::BCVBR<16>;
Expand Down Expand Up @@ -83,6 +83,10 @@ enum BlockID {
/// The enum constant data block, which maps enumerator names to
/// information about the enumerators.
ENUM_CONSTANT_BLOCK_ID,

/// The enum constant data block, which maps member function names to
/// information about the member function.
MEMBER_FUNCTION_BLOCK_ID,
};

namespace control_block {
Expand Down Expand Up @@ -211,6 +215,16 @@ using GlobalFunctionDataLayout = llvm::BCRecordLayout<
>;
} // namespace global_function_block

namespace member_function_block {
enum { MEMBER_FUNCTION_DATA = 1 };

using MemberFunctionDataLayout = llvm::BCRecordLayout<
MEMBER_FUNCTION_DATA, // record ID
llvm::BCVBR<16>, // table offset within the blob (see below)
llvm::BCBlob // map from name to global function information
>;
} // namespace global_function_block

namespace tag_block {
enum { TAG_DATA = 1 };

Expand Down
152 changes: 152 additions & 0 deletions clang/lib/APINotes/APINotesReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,14 @@ namespace {
= endian::readNext<uint16_t, little, unaligned>(data);
info.ResultType = std::string(data, data + resultTypeLen);
data += resultTypeLen;

unsigned importAsLength =
endian::readNext<uint16_t, little, unaligned>(data);
if (importAsLength > 0) {
info.SwiftImportAs =
std::string(reinterpret_cast<const char *>(data), importAsLength-1);
data += importAsLength-1;
}
}

/// Used to deserialize the on-disk Objective-C method table.
Expand Down Expand Up @@ -465,6 +473,24 @@ namespace {
}
};

/// Used to deserialize the on-disk global function table.
class MemberFunctionTableInfo
: public VersionedTableInfo<MemberFunctionTableInfo, unsigned,
GlobalFunctionInfo> {
public:
static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
auto nameID = endian::readNext<uint32_t, little, unaligned>(data);
return nameID;
}

static GlobalFunctionInfo readUnversioned(internal_key_type key,
const uint8_t *&data) {
GlobalFunctionInfo info;
readFunctionInfo(data, info);
return info;
}
};

/// Used to deserialize the on-disk enumerator table.
class EnumConstantTableInfo
: public VersionedTableInfo<EnumConstantTableInfo, unsigned,
Expand Down Expand Up @@ -506,6 +532,26 @@ namespace {
static_cast<EnumExtensibilityKind>((payload & 0x3) - 1);
}

auto readStringIfPresent = [&]() -> llvm::Optional<std::string> {
unsigned len =
endian::readNext<uint16_t, little, unaligned>(data);
if (len > 0) {
auto out = std::string(reinterpret_cast<const char *>(data), len-1);
data += len-1;
return out;
}
return None;
};

if (auto importAs = readStringIfPresent())
info.SwiftImportAs = importAs;

if (auto importAs = readStringIfPresent())
info.SwiftRetainOp = importAs;

if (auto importAs = readStringIfPresent())
info.SwiftReleaseOp = importAs;

readCommonTypeInfo(data, info);
return info;
}
Expand Down Expand Up @@ -604,6 +650,11 @@ class APINotesReader::Implementation {
/// The global function table.
std::unique_ptr<SerializedGlobalFunctionTable> GlobalFunctionTable;

using SerializedMemberFunctionTable =
llvm::OnDiskIterableChainedHashTable<MemberFunctionTableInfo>;

std::unique_ptr<SerializedMemberFunctionTable> MemberFunctionTable;

using SerializedEnumConstantTable =
llvm::OnDiskIterableChainedHashTable<EnumConstantTableInfo>;

Expand Down Expand Up @@ -646,6 +697,8 @@ class APINotesReader::Implementation {
SmallVectorImpl<uint64_t> &scratch);
bool readGlobalFunctionBlock(llvm::BitstreamCursor &cursor,
SmallVectorImpl<uint64_t> &scratch);
bool readMemberFunctionBlock(llvm::BitstreamCursor &cursor,
SmallVectorImpl<uint64_t> &scratch);
bool readEnumConstantBlock(llvm::BitstreamCursor &cursor,
SmallVectorImpl<uint64_t> &scratch);
bool readTagBlock(llvm::BitstreamCursor &cursor,
Expand Down Expand Up @@ -1344,6 +1397,84 @@ bool APINotesReader::Implementation::readGlobalFunctionBlock(
return false;
}

bool APINotesReader::Implementation::readMemberFunctionBlock(
llvm::BitstreamCursor &cursor,
SmallVectorImpl<uint64_t> &scratch) {
if (cursor.EnterSubBlock(MEMBER_FUNCTION_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();
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 member_function_block::MEMBER_FUNCTION_DATA: {
// Already saw global function table.
if (MemberFunctionTable)
return true;

uint32_t tableOffset;
member_function_block::MemberFunctionDataLayout::readRecord(scratch,
tableOffset);
auto base = reinterpret_cast<const uint8_t *>(blobData.data());

MemberFunctionTable.reset(
SerializedMemberFunctionTable::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::readEnumConstantBlock(
llvm::BitstreamCursor &cursor,
SmallVectorImpl<uint64_t> &scratch) {
Expand Down Expand Up @@ -1697,6 +1828,14 @@ APINotesReader::APINotesReader(llvm::MemoryBuffer *inputBuffer,
}
break;

case MEMBER_FUNCTION_BLOCK_ID:
if (!hasValidControlBlock ||
Impl.readMemberFunctionBlock(cursor, scratch)) {
failed = true;
return;
}
break;

case ENUM_CONSTANT_BLOCK_ID:
if (!hasValidControlBlock ||
Impl.readEnumConstantBlock(cursor, scratch)) {
Expand Down Expand Up @@ -1952,6 +2091,19 @@ auto APINotesReader::lookupGlobalFunction(StringRef name)
return { Impl.SwiftVersion, *known };
}

auto APINotesReader::lookupMemberFunction(llvm::StringRef name)
-> VersionedInfo<GlobalFunctionInfo> {
Optional<IdentifierID> nameID = Impl.getIdentifier(name);
if (!nameID)
return None;

auto known = Impl.MemberFunctionTable->find(*nameID);
if (known == Impl.MemberFunctionTable->end())
return None;

return { Impl.SwiftVersion, *known };
}

auto APINotesReader::lookupEnumConstant(StringRef name)
-> VersionedInfo<EnumConstantInfo> {
if (!Impl.EnumConstantTable)
Expand Down
Loading