Skip to content

[APINotes] Support SwiftImportAs for C++ structs #7386

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 1 commit into from
Sep 5, 2023
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
14 changes: 14 additions & 0 deletions clang/include/clang/APINotes/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,10 @@ class TagInfo : public CommonTypeInfo {
unsigned IsFlagEnum : 1;

public:
std::optional<std::string> SwiftImportAs;
std::optional<std::string> SwiftRetainOp;
std::optional<std::string> SwiftReleaseOp;

std::optional<EnumExtensibilityKind> EnumExtensibility;

TagInfo() : HasFlagEnum(0), IsFlagEnum(0) {}
Expand All @@ -679,6 +683,13 @@ class TagInfo : public CommonTypeInfo {
TagInfo &operator|=(const TagInfo &RHS) {
static_cast<CommonTypeInfo &>(*this) |= RHS;

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

if (!HasFlagEnum)
setFlagEnum(RHS.isFlagEnum());

Expand All @@ -695,6 +706,9 @@ class TagInfo : public CommonTypeInfo {

inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
return static_cast<const CommonTypeInfo &>(LHS) == RHS &&
LHS.SwiftImportAs == RHS.SwiftImportAs &&
LHS.SwiftRetainOp == RHS.SwiftRetainOp &&
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp &&
LHS.isFlagEnum() == RHS.isFlagEnum() &&
LHS.EnumExtensibility == RHS.EnumExtensibility;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/APINotes/APINotesFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,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; // SwiftImportAs

using IdentifierID = llvm::PointerEmbeddedInt<unsigned, 31>;
using IdentifierIDField = llvm::BCVBR<16>;
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/APINotes/APINotesReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,28 @@ namespace {
static_cast<EnumExtensibilityKind>((payload & 0x3) - 1);
}

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;
}
unsigned RetainOpLength =
endian::readNext<uint16_t, little, unaligned>(data);
if (RetainOpLength > 0) {
info.SwiftRetainOp = std::string(reinterpret_cast<const char *>(data),
RetainOpLength - 1);
data += RetainOpLength - 1;
}
unsigned ReleaseOpLength =
endian::readNext<uint16_t, little, unaligned>(data);
if (ReleaseOpLength > 0) {
info.SwiftReleaseOp = std::string(reinterpret_cast<const char *>(data),
ReleaseOpLength - 1);
data += ReleaseOpLength - 1;
}

readCommonTypeInfo(data, info);
return info;
}
Expand Down
24 changes: 23 additions & 1 deletion clang/lib/APINotes/APINotesWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,10 @@ class CommonTypeTableInfo
class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
public:
unsigned getUnversionedInfoSize(const TagInfo &TI) {
return 1 + getCommonTypeInfoSize(TI);
return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
1 + getCommonTypeInfoSize(TI);
}

void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
Expand All @@ -1164,6 +1167,25 @@ class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {

writer.write<uint8_t>(Flags);

if (auto ImportAs = TI.SwiftImportAs) {
writer.write<uint16_t>(ImportAs->size() + 1);
OS.write(ImportAs->c_str(), ImportAs->size());
} else {
writer.write<uint16_t>(0);
}
if (auto RetainOp = TI.SwiftRetainOp) {
writer.write<uint16_t>(RetainOp->size() + 1);
OS.write(RetainOp->c_str(), RetainOp->size());
} else {
writer.write<uint16_t>(0);
}
if (auto ReleaseOp = TI.SwiftReleaseOp) {
writer.write<uint16_t>(ReleaseOp->size() + 1);
OS.write(ReleaseOp->c_str(), ReleaseOp->size());
} else {
writer.write<uint16_t>(0);
}

emitCommonTypeInfo(OS, TI);
}
};
Expand Down
27 changes: 27 additions & 0 deletions clang/lib/APINotes/APINotesYAMLCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,9 @@ struct Tag {
std::optional<bool> SwiftPrivate;
std::optional<StringRef> SwiftBridge;
std::optional<StringRef> NSErrorDomain;
std::optional<std::string> SwiftImportAs;
std::optional<std::string> SwiftRetainOp;
std::optional<std::string> SwiftReleaseOp;
std::optional<EnumExtensibilityKind> EnumExtensibility;
std::optional<bool> FlagEnum;
std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
Expand Down Expand Up @@ -557,6 +560,9 @@ template <> struct MappingTraits<Tag> {
IO.mapOptional("SwiftName", T.SwiftName, StringRef(""));
IO.mapOptional("SwiftBridge", T.SwiftBridge);
IO.mapOptional("NSErrorDomain", T.NSErrorDomain);
IO.mapOptional("SwiftImportAs", T.SwiftImportAs);
IO.mapOptional("SwiftReleaseOp", T.SwiftReleaseOp);
IO.mapOptional("SwiftRetainOp", T.SwiftRetainOp);
IO.mapOptional("EnumExtensibility", T.EnumExtensibility);
IO.mapOptional("FlagEnum", T.FlagEnum);
IO.mapOptional("EnumKind", T.EnumConvenienceKind);
Expand Down Expand Up @@ -1129,6 +1135,27 @@ namespace {
if (convertCommonType(t, tagInfo, t.Name))
continue;

if ((t.SwiftRetainOp.has_value() || t.SwiftReleaseOp.has_value()) &&
!t.SwiftImportAs) {
emitError(llvm::Twine("should declare SwiftImportAs to use "
"SwiftRetainOp and SwiftReleaseOp (for ") +
t.Name + ")");
continue;
}
if (t.SwiftReleaseOp.has_value() != t.SwiftRetainOp.has_value()) {
emitError(llvm::Twine("should declare both SwiftReleaseOp and "
"SwiftRetainOp (for ") +
t.Name + ")");
continue;
}

if (t.SwiftImportAs)
tagInfo.SwiftImportAs = t.SwiftImportAs;
if (t.SwiftRetainOp)
tagInfo.SwiftRetainOp = t.SwiftRetainOp;
if (t.SwiftReleaseOp)
tagInfo.SwiftReleaseOp = t.SwiftReleaseOp;

if (t.EnumConvenienceKind) {
if (t.EnumExtensibility) {
emitError(llvm::Twine(
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/Sema/SemaAPINotes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,22 @@ static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D,
static void ProcessAPINotes(Sema &S, TagDecl *D,
const api_notes::TagInfo &info,
VersionedInfoMetadata metadata) {
if (auto ImportAs = info.SwiftImportAs) {
auto str = "import_" + ImportAs.value();
auto attr = SwiftAttrAttr::Create(S.Context, str);
D->addAttr(attr);
}
if (auto RetainOp = info.SwiftRetainOp) {
auto str = "retain:" + RetainOp.value();
auto attr = SwiftAttrAttr::Create(S.Context, str);
D->addAttr(attr);
}
if (auto ReleaseOp = info.SwiftReleaseOp) {
auto str = "release:" + ReleaseOp.value();
auto attr = SwiftAttrAttr::Create(S.Context, str);
D->addAttr(attr);
}

if (auto extensibility = info.EnumExtensibility) {
using api_notes::EnumExtensibilityKind;
bool shouldAddAttribute = (*extensibility != EnumExtensibilityKind::None);
Expand Down
9 changes: 9 additions & 0 deletions clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
Name: SwiftImportAs
Tags:
- Name: ImmortalRefType
SwiftImportAs: reference
- Name: RefCountedType
SwiftImportAs: reference
SwiftReleaseOp: RCRelease
SwiftRetainOp: RCRetain
6 changes: 6 additions & 0 deletions clang/test/APINotes/Inputs/Headers/SwiftImportAs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
struct ImmortalRefType {};

struct RefCountedType { int value; };

inline void RCRetain(RefCountedType *x) { x->value++; }
inline void RCRelease(RefCountedType *x) { x->value--; }
4 changes: 4 additions & 0 deletions clang/test/APINotes/Inputs/Headers/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ module ModuleWithWrongCasePrivate {
module Namespaces {
header "Namespaces.h"
}

module SwiftImportAs {
header "SwiftImportAs.h"
}
16 changes: 16 additions & 0 deletions clang/test/APINotes/swift-import-as.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter ImmortalRefType | FileCheck -check-prefix=CHECK-IMMORTAL %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter RefCountedType | FileCheck -check-prefix=CHECK-REF-COUNTED %s

#include <SwiftImportAs.h>

// CHECK-IMMORTAL: Dumping ImmortalRefType:
// CHECK-IMMORTAL-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct ImmortalRefType
// CHECK-IMMORTAL: SwiftAttrAttr {{.+}} <<invalid sloc>> "import_reference"

// CHECK-REF-COUNTED: Dumping RefCountedType:
// CHECK-REF-COUNTED-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct RefCountedType
// CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "import_reference"
// CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "retain:RCRetain"
// CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "release:RCRelease"