Skip to content

Commit 1279ac6

Browse files
authored
Merge pull request #7386 from apple/egorzhdan/apinotes-importas
[APINotes] Support `SwiftImportAs` for C++ structs
2 parents 88a681b + e751b39 commit 1279ac6

File tree

10 files changed

+138
-2
lines changed

10 files changed

+138
-2
lines changed

clang/include/clang/APINotes/Types.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,10 @@ class TagInfo : public CommonTypeInfo {
662662
unsigned IsFlagEnum : 1;
663663

664664
public:
665+
std::optional<std::string> SwiftImportAs;
666+
std::optional<std::string> SwiftRetainOp;
667+
std::optional<std::string> SwiftReleaseOp;
668+
665669
std::optional<EnumExtensibilityKind> EnumExtensibility;
666670

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

686+
if (!SwiftImportAs)
687+
SwiftImportAs = RHS.SwiftImportAs;
688+
if (!SwiftRetainOp)
689+
SwiftRetainOp = RHS.SwiftRetainOp;
690+
if (!SwiftReleaseOp)
691+
SwiftReleaseOp = RHS.SwiftReleaseOp;
692+
682693
if (!HasFlagEnum)
683694
setFlagEnum(RHS.isFlagEnum());
684695

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

696707
inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
697708
return static_cast<const CommonTypeInfo &>(LHS) == RHS &&
709+
LHS.SwiftImportAs == RHS.SwiftImportAs &&
710+
LHS.SwiftRetainOp == RHS.SwiftRetainOp &&
711+
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp &&
698712
LHS.isFlagEnum() == RHS.isFlagEnum() &&
699713
LHS.EnumExtensibility == RHS.EnumExtensibility;
700714
}

clang/lib/APINotes/APINotesFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const uint16_t VERSION_MAJOR = 0;
2424
/// API notes file minor version number.
2525
///
2626
/// When the format changes IN ANY WAY, this number should be incremented.
27-
const uint16_t VERSION_MINOR = 24; // EnumExtensibility + FlagEnum
27+
const uint16_t VERSION_MINOR = 25; // SwiftImportAs
2828

2929
using IdentifierID = llvm::PointerEmbeddedInt<unsigned, 31>;
3030
using IdentifierIDField = llvm::BCVBR<16>;

clang/lib/APINotes/APINotesReader.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,28 @@ namespace {
536536
static_cast<EnumExtensibilityKind>((payload & 0x3) - 1);
537537
}
538538

539+
unsigned ImportAsLength =
540+
endian::readNext<uint16_t, little, unaligned>(data);
541+
if (ImportAsLength > 0) {
542+
info.SwiftImportAs = std::string(reinterpret_cast<const char *>(data),
543+
ImportAsLength - 1);
544+
data += ImportAsLength - 1;
545+
}
546+
unsigned RetainOpLength =
547+
endian::readNext<uint16_t, little, unaligned>(data);
548+
if (RetainOpLength > 0) {
549+
info.SwiftRetainOp = std::string(reinterpret_cast<const char *>(data),
550+
RetainOpLength - 1);
551+
data += RetainOpLength - 1;
552+
}
553+
unsigned ReleaseOpLength =
554+
endian::readNext<uint16_t, little, unaligned>(data);
555+
if (ReleaseOpLength > 0) {
556+
info.SwiftReleaseOp = std::string(reinterpret_cast<const char *>(data),
557+
ReleaseOpLength - 1);
558+
data += ReleaseOpLength - 1;
559+
}
560+
539561
readCommonTypeInfo(data, info);
540562
return info;
541563
}

clang/lib/APINotes/APINotesWriter.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1146,7 +1146,10 @@ class CommonTypeTableInfo
11461146
class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
11471147
public:
11481148
unsigned getUnversionedInfoSize(const TagInfo &TI) {
1149-
return 1 + getCommonTypeInfoSize(TI);
1149+
return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
1150+
2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
1151+
2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
1152+
1 + getCommonTypeInfoSize(TI);
11501153
}
11511154

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

11651168
writer.write<uint8_t>(Flags);
11661169

1170+
if (auto ImportAs = TI.SwiftImportAs) {
1171+
writer.write<uint16_t>(ImportAs->size() + 1);
1172+
OS.write(ImportAs->c_str(), ImportAs->size());
1173+
} else {
1174+
writer.write<uint16_t>(0);
1175+
}
1176+
if (auto RetainOp = TI.SwiftRetainOp) {
1177+
writer.write<uint16_t>(RetainOp->size() + 1);
1178+
OS.write(RetainOp->c_str(), RetainOp->size());
1179+
} else {
1180+
writer.write<uint16_t>(0);
1181+
}
1182+
if (auto ReleaseOp = TI.SwiftReleaseOp) {
1183+
writer.write<uint16_t>(ReleaseOp->size() + 1);
1184+
OS.write(ReleaseOp->c_str(), ReleaseOp->size());
1185+
} else {
1186+
writer.write<uint16_t>(0);
1187+
}
1188+
11671189
emitCommonTypeInfo(OS, TI);
11681190
}
11691191
};

clang/lib/APINotes/APINotesYAMLCompiler.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,9 @@ struct Tag {
527527
std::optional<bool> SwiftPrivate;
528528
std::optional<StringRef> SwiftBridge;
529529
std::optional<StringRef> NSErrorDomain;
530+
std::optional<std::string> SwiftImportAs;
531+
std::optional<std::string> SwiftRetainOp;
532+
std::optional<std::string> SwiftReleaseOp;
530533
std::optional<EnumExtensibilityKind> EnumExtensibility;
531534
std::optional<bool> FlagEnum;
532535
std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
@@ -557,6 +560,9 @@ template <> struct MappingTraits<Tag> {
557560
IO.mapOptional("SwiftName", T.SwiftName, StringRef(""));
558561
IO.mapOptional("SwiftBridge", T.SwiftBridge);
559562
IO.mapOptional("NSErrorDomain", T.NSErrorDomain);
563+
IO.mapOptional("SwiftImportAs", T.SwiftImportAs);
564+
IO.mapOptional("SwiftReleaseOp", T.SwiftReleaseOp);
565+
IO.mapOptional("SwiftRetainOp", T.SwiftRetainOp);
560566
IO.mapOptional("EnumExtensibility", T.EnumExtensibility);
561567
IO.mapOptional("FlagEnum", T.FlagEnum);
562568
IO.mapOptional("EnumKind", T.EnumConvenienceKind);
@@ -1129,6 +1135,27 @@ namespace {
11291135
if (convertCommonType(t, tagInfo, t.Name))
11301136
continue;
11311137

1138+
if ((t.SwiftRetainOp.has_value() || t.SwiftReleaseOp.has_value()) &&
1139+
!t.SwiftImportAs) {
1140+
emitError(llvm::Twine("should declare SwiftImportAs to use "
1141+
"SwiftRetainOp and SwiftReleaseOp (for ") +
1142+
t.Name + ")");
1143+
continue;
1144+
}
1145+
if (t.SwiftReleaseOp.has_value() != t.SwiftRetainOp.has_value()) {
1146+
emitError(llvm::Twine("should declare both SwiftReleaseOp and "
1147+
"SwiftRetainOp (for ") +
1148+
t.Name + ")");
1149+
continue;
1150+
}
1151+
1152+
if (t.SwiftImportAs)
1153+
tagInfo.SwiftImportAs = t.SwiftImportAs;
1154+
if (t.SwiftRetainOp)
1155+
tagInfo.SwiftRetainOp = t.SwiftRetainOp;
1156+
if (t.SwiftReleaseOp)
1157+
tagInfo.SwiftReleaseOp = t.SwiftReleaseOp;
1158+
11321159
if (t.EnumConvenienceKind) {
11331160
if (t.EnumExtensibility) {
11341161
emitError(llvm::Twine(

clang/lib/Sema/SemaAPINotes.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,22 @@ static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D,
628628
static void ProcessAPINotes(Sema &S, TagDecl *D,
629629
const api_notes::TagInfo &info,
630630
VersionedInfoMetadata metadata) {
631+
if (auto ImportAs = info.SwiftImportAs) {
632+
auto str = "import_" + ImportAs.value();
633+
auto attr = SwiftAttrAttr::Create(S.Context, str);
634+
D->addAttr(attr);
635+
}
636+
if (auto RetainOp = info.SwiftRetainOp) {
637+
auto str = "retain:" + RetainOp.value();
638+
auto attr = SwiftAttrAttr::Create(S.Context, str);
639+
D->addAttr(attr);
640+
}
641+
if (auto ReleaseOp = info.SwiftReleaseOp) {
642+
auto str = "release:" + ReleaseOp.value();
643+
auto attr = SwiftAttrAttr::Create(S.Context, str);
644+
D->addAttr(attr);
645+
}
646+
631647
if (auto extensibility = info.EnumExtensibility) {
632648
using api_notes::EnumExtensibilityKind;
633649
bool shouldAddAttribute = (*extensibility != EnumExtensibilityKind::None);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
Name: SwiftImportAs
3+
Tags:
4+
- Name: ImmortalRefType
5+
SwiftImportAs: reference
6+
- Name: RefCountedType
7+
SwiftImportAs: reference
8+
SwiftReleaseOp: RCRelease
9+
SwiftRetainOp: RCRetain
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
struct ImmortalRefType {};
2+
3+
struct RefCountedType { int value; };
4+
5+
inline void RCRetain(RefCountedType *x) { x->value++; }
6+
inline void RCRelease(RefCountedType *x) { x->value--; }

clang/test/APINotes/Inputs/Headers/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ module ModuleWithWrongCasePrivate {
2525
module Namespaces {
2626
header "Namespaces.h"
2727
}
28+
29+
module SwiftImportAs {
30+
header "SwiftImportAs.h"
31+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
// 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++
3+
// 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
4+
// 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
5+
6+
#include <SwiftImportAs.h>
7+
8+
// CHECK-IMMORTAL: Dumping ImmortalRefType:
9+
// CHECK-IMMORTAL-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct ImmortalRefType
10+
// CHECK-IMMORTAL: SwiftAttrAttr {{.+}} <<invalid sloc>> "import_reference"
11+
12+
// CHECK-REF-COUNTED: Dumping RefCountedType:
13+
// CHECK-REF-COUNTED-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct RefCountedType
14+
// CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "import_reference"
15+
// CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "retain:RCRetain"
16+
// CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "release:RCRelease"

0 commit comments

Comments
 (0)