Skip to content

Commit 219773f

Browse files
authored
Merge pull request #5021 from zoecarver/cxx-api-notes-support
[🍒][apinotes][cxx-interop] Add support for namespaces, nested tags, and methods.
2 parents e41a0a1 + f0bd7fe commit 219773f

File tree

11 files changed

+513
-59
lines changed

11 files changed

+513
-59
lines changed

clang/include/clang/APINotes/APINotesReader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ class APINotesReader {
184184
/// \returns information about the global function, if known.
185185
VersionedInfo<GlobalFunctionInfo> lookupGlobalFunction(llvm::StringRef name);
186186

187+
VersionedInfo<GlobalFunctionInfo> lookupMemberFunction(llvm::StringRef name);
188+
187189
/// Look for information regarding the given enumerator.
188190
///
189191
/// \param name The name of the enumerator.

clang/include/clang/APINotes/APINotesWriter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ class APINotesWriter {
9393
void addGlobalFunction(llvm::StringRef name, const GlobalFunctionInfo &info,
9494
llvm::VersionTuple swiftVersion);
9595

96+
void addMemberFunction(llvm::StringRef name, const FunctionInfo &info,
97+
llvm::VersionTuple swiftVersion);
98+
9699
/// Add information about an enumerator.
97100
///
98101
/// \param name The name of this enumerator.

clang/include/clang/APINotes/Types.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,8 @@ class FunctionInfo : public CommonEntityInfo {
513513
/// The function parameters.
514514
std::vector<ParamInfo> Params;
515515

516+
llvm::Optional<std::string> SwiftImportAs;
517+
516518
FunctionInfo()
517519
: CommonEntityInfo(), NullabilityAudited(false), NumAdjustedNullable(0),
518520
RawRetainCountConvention() {}
@@ -665,6 +667,10 @@ class TagInfo : public CommonTypeInfo {
665667
public:
666668
llvm::Optional<EnumExtensibilityKind> EnumExtensibility;
667669

670+
llvm::Optional<std::string> SwiftImportAs;
671+
llvm::Optional<std::string> SwiftRetainOp;
672+
llvm::Optional<std::string> SwiftReleaseOp;
673+
668674
TagInfo() : CommonTypeInfo(), HasFlagEnum(0), IsFlagEnum(0) {}
669675

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

695+
if (!SwiftImportAs)
696+
SwiftImportAs = RHS.SwiftImportAs;
697+
if (!SwiftRetainOp)
698+
SwiftImportAs = RHS.SwiftRetainOp;
699+
if (!SwiftReleaseOp)
700+
SwiftImportAs = RHS.SwiftReleaseOp;
701+
689702
return *this;
690703
}
691704

@@ -697,7 +710,10 @@ class TagInfo : public CommonTypeInfo {
697710
inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
698711
return static_cast<const CommonTypeInfo &>(LHS) == RHS &&
699712
LHS.isFlagEnum() == RHS.isFlagEnum() &&
700-
LHS.EnumExtensibility == RHS.EnumExtensibility;
713+
LHS.EnumExtensibility == RHS.EnumExtensibility &&
714+
LHS.SwiftImportAs == RHS.SwiftImportAs &&
715+
LHS.SwiftRetainOp == RHS.SwiftRetainOp &&
716+
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp;
701717
}
702718

703719
inline bool operator!=(const TagInfo &LHS, const TagInfo &RHS) {

clang/lib/APINotes/APINotesFormat.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const uint16_t VERSION_MAJOR = 0;
2323
/// API notes file minor version number.
2424
///
2525
/// When the format changes IN ANY WAY, this number should be incremented.
26-
const uint16_t VERSION_MINOR = 24; // EnumExtensibility + FlagEnum
26+
const uint16_t VERSION_MINOR = 25; // Member functions
2727

2828
using IdentifierID = llvm::PointerEmbeddedInt<unsigned, 31>;
2929
using IdentifierIDField = llvm::BCVBR<16>;
@@ -83,6 +83,10 @@ enum BlockID {
8383
/// The enum constant data block, which maps enumerator names to
8484
/// information about the enumerators.
8585
ENUM_CONSTANT_BLOCK_ID,
86+
87+
/// The enum constant data block, which maps member function names to
88+
/// information about the member function.
89+
MEMBER_FUNCTION_BLOCK_ID,
8690
};
8791

8892
namespace control_block {
@@ -211,6 +215,16 @@ using GlobalFunctionDataLayout = llvm::BCRecordLayout<
211215
>;
212216
} // namespace global_function_block
213217

218+
namespace member_function_block {
219+
enum { MEMBER_FUNCTION_DATA = 1 };
220+
221+
using MemberFunctionDataLayout = llvm::BCRecordLayout<
222+
MEMBER_FUNCTION_DATA, // record ID
223+
llvm::BCVBR<16>, // table offset within the blob (see below)
224+
llvm::BCBlob // map from name to global function information
225+
>;
226+
} // namespace global_function_block
227+
214228
namespace tag_block {
215229
enum { TAG_DATA = 1 };
216230

clang/lib/APINotes/APINotesReader.cpp

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,14 @@ namespace {
351351
= endian::readNext<uint16_t, little, unaligned>(data);
352352
info.ResultType = std::string(data, data + resultTypeLen);
353353
data += resultTypeLen;
354+
355+
unsigned importAsLength =
356+
endian::readNext<uint16_t, little, unaligned>(data);
357+
if (importAsLength > 0) {
358+
info.SwiftImportAs =
359+
std::string(reinterpret_cast<const char *>(data), importAsLength-1);
360+
data += importAsLength-1;
361+
}
354362
}
355363

356364
/// Used to deserialize the on-disk Objective-C method table.
@@ -465,6 +473,24 @@ namespace {
465473
}
466474
};
467475

476+
/// Used to deserialize the on-disk global function table.
477+
class MemberFunctionTableInfo
478+
: public VersionedTableInfo<MemberFunctionTableInfo, unsigned,
479+
GlobalFunctionInfo> {
480+
public:
481+
static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
482+
auto nameID = endian::readNext<uint32_t, little, unaligned>(data);
483+
return nameID;
484+
}
485+
486+
static GlobalFunctionInfo readUnversioned(internal_key_type key,
487+
const uint8_t *&data) {
488+
GlobalFunctionInfo info;
489+
readFunctionInfo(data, info);
490+
return info;
491+
}
492+
};
493+
468494
/// Used to deserialize the on-disk enumerator table.
469495
class EnumConstantTableInfo
470496
: public VersionedTableInfo<EnumConstantTableInfo, unsigned,
@@ -506,6 +532,26 @@ namespace {
506532
static_cast<EnumExtensibilityKind>((payload & 0x3) - 1);
507533
}
508534

535+
auto readStringIfPresent = [&]() -> llvm::Optional<std::string> {
536+
unsigned len =
537+
endian::readNext<uint16_t, little, unaligned>(data);
538+
if (len > 0) {
539+
auto out = std::string(reinterpret_cast<const char *>(data), len-1);
540+
data += len-1;
541+
return out;
542+
}
543+
return None;
544+
};
545+
546+
if (auto importAs = readStringIfPresent())
547+
info.SwiftImportAs = importAs;
548+
549+
if (auto importAs = readStringIfPresent())
550+
info.SwiftRetainOp = importAs;
551+
552+
if (auto importAs = readStringIfPresent())
553+
info.SwiftReleaseOp = importAs;
554+
509555
readCommonTypeInfo(data, info);
510556
return info;
511557
}
@@ -604,6 +650,11 @@ class APINotesReader::Implementation {
604650
/// The global function table.
605651
std::unique_ptr<SerializedGlobalFunctionTable> GlobalFunctionTable;
606652

653+
using SerializedMemberFunctionTable =
654+
llvm::OnDiskIterableChainedHashTable<MemberFunctionTableInfo>;
655+
656+
std::unique_ptr<SerializedMemberFunctionTable> MemberFunctionTable;
657+
607658
using SerializedEnumConstantTable =
608659
llvm::OnDiskIterableChainedHashTable<EnumConstantTableInfo>;
609660

@@ -646,6 +697,8 @@ class APINotesReader::Implementation {
646697
SmallVectorImpl<uint64_t> &scratch);
647698
bool readGlobalFunctionBlock(llvm::BitstreamCursor &cursor,
648699
SmallVectorImpl<uint64_t> &scratch);
700+
bool readMemberFunctionBlock(llvm::BitstreamCursor &cursor,
701+
SmallVectorImpl<uint64_t> &scratch);
649702
bool readEnumConstantBlock(llvm::BitstreamCursor &cursor,
650703
SmallVectorImpl<uint64_t> &scratch);
651704
bool readTagBlock(llvm::BitstreamCursor &cursor,
@@ -1344,6 +1397,84 @@ bool APINotesReader::Implementation::readGlobalFunctionBlock(
13441397
return false;
13451398
}
13461399

1400+
bool APINotesReader::Implementation::readMemberFunctionBlock(
1401+
llvm::BitstreamCursor &cursor,
1402+
SmallVectorImpl<uint64_t> &scratch) {
1403+
if (cursor.EnterSubBlock(MEMBER_FUNCTION_BLOCK_ID))
1404+
return true;
1405+
1406+
llvm::Expected<llvm::BitstreamEntry> maybeNext = cursor.advance();
1407+
if (!maybeNext) {
1408+
// FIXME this drops the error on the floor.
1409+
consumeError(maybeNext.takeError());
1410+
return false;
1411+
}
1412+
llvm::BitstreamEntry next = maybeNext.get();
1413+
while (next.Kind != llvm::BitstreamEntry::EndBlock) {
1414+
if (next.Kind == llvm::BitstreamEntry::Error)
1415+
return true;
1416+
1417+
if (next.Kind == llvm::BitstreamEntry::SubBlock) {
1418+
// Unknown sub-block, possibly for use by a future version of the
1419+
// API notes format.
1420+
if (cursor.SkipBlock())
1421+
return true;
1422+
1423+
maybeNext = cursor.advance();
1424+
if (!maybeNext) {
1425+
// FIXME this drops the error on the floor.
1426+
consumeError(maybeNext.takeError());
1427+
return false;
1428+
}
1429+
next = maybeNext.get();
1430+
continue;
1431+
}
1432+
1433+
scratch.clear();
1434+
StringRef blobData;
1435+
llvm::Expected<unsigned> maybeKind = cursor.readRecord(next.ID, scratch, &blobData);
1436+
if (!maybeKind) {
1437+
// FIXME this drops the error on the floor.
1438+
consumeError(maybeKind.takeError());
1439+
return false;
1440+
}
1441+
unsigned kind = maybeKind.get();
1442+
switch (kind) {
1443+
case member_function_block::MEMBER_FUNCTION_DATA: {
1444+
// Already saw global function table.
1445+
if (MemberFunctionTable)
1446+
return true;
1447+
1448+
uint32_t tableOffset;
1449+
member_function_block::MemberFunctionDataLayout::readRecord(scratch,
1450+
tableOffset);
1451+
auto base = reinterpret_cast<const uint8_t *>(blobData.data());
1452+
1453+
MemberFunctionTable.reset(
1454+
SerializedMemberFunctionTable::Create(base + tableOffset,
1455+
base + sizeof(uint32_t),
1456+
base));
1457+
break;
1458+
}
1459+
1460+
default:
1461+
// Unknown record, possibly for use by a future version of the
1462+
// module format.
1463+
break;
1464+
}
1465+
1466+
maybeNext = cursor.advance();
1467+
if (!maybeNext) {
1468+
// FIXME this drops the error on the floor.
1469+
consumeError(maybeNext.takeError());
1470+
return false;
1471+
}
1472+
next = maybeNext.get();
1473+
}
1474+
1475+
return false;
1476+
}
1477+
13471478
bool APINotesReader::Implementation::readEnumConstantBlock(
13481479
llvm::BitstreamCursor &cursor,
13491480
SmallVectorImpl<uint64_t> &scratch) {
@@ -1697,6 +1828,14 @@ APINotesReader::APINotesReader(llvm::MemoryBuffer *inputBuffer,
16971828
}
16981829
break;
16991830

1831+
case MEMBER_FUNCTION_BLOCK_ID:
1832+
if (!hasValidControlBlock ||
1833+
Impl.readMemberFunctionBlock(cursor, scratch)) {
1834+
failed = true;
1835+
return;
1836+
}
1837+
break;
1838+
17001839
case ENUM_CONSTANT_BLOCK_ID:
17011840
if (!hasValidControlBlock ||
17021841
Impl.readEnumConstantBlock(cursor, scratch)) {
@@ -1952,6 +2091,19 @@ auto APINotesReader::lookupGlobalFunction(StringRef name)
19522091
return { Impl.SwiftVersion, *known };
19532092
}
19542093

2094+
auto APINotesReader::lookupMemberFunction(llvm::StringRef name)
2095+
-> VersionedInfo<GlobalFunctionInfo> {
2096+
Optional<IdentifierID> nameID = Impl.getIdentifier(name);
2097+
if (!nameID)
2098+
return None;
2099+
2100+
auto known = Impl.MemberFunctionTable->find(*nameID);
2101+
if (known == Impl.MemberFunctionTable->end())
2102+
return None;
2103+
2104+
return { Impl.SwiftVersion, *known };
2105+
}
2106+
19552107
auto APINotesReader::lookupEnumConstant(StringRef name)
19562108
-> VersionedInfo<EnumConstantInfo> {
19572109
if (!Impl.EnumConstantTable)

0 commit comments

Comments
 (0)