Skip to content

Commit 75786f3

Browse files
authored
Merge pull request #7387 from apple/egorzhdan/apinotes-importas-20221013
🍒[APINotes] Support `SwiftImportAs` for C++ structs
2 parents 91de708 + 7b7a3e4 commit 75786f3

File tree

10 files changed

+145
-10
lines changed

10 files changed

+145
-10
lines changed

clang/include/clang/APINotes/Types.h

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

659659
public:
660+
llvm::Optional<std::string> SwiftImportAs;
661+
llvm::Optional<std::string> SwiftRetainOp;
662+
llvm::Optional<std::string> SwiftReleaseOp;
663+
660664
llvm::Optional<EnumExtensibilityKind> EnumExtensibility;
661665

662666
TagInfo() : HasFlagEnum(0), IsFlagEnum(0) {}
@@ -674,6 +678,13 @@ class TagInfo : public CommonTypeInfo {
674678
TagInfo &operator|=(const TagInfo &RHS) {
675679
static_cast<CommonTypeInfo &>(*this) |= RHS;
676680

681+
if (!SwiftImportAs)
682+
SwiftImportAs = RHS.SwiftImportAs;
683+
if (!SwiftRetainOp)
684+
SwiftRetainOp = RHS.SwiftRetainOp;
685+
if (!SwiftReleaseOp)
686+
SwiftReleaseOp = RHS.SwiftReleaseOp;
687+
677688
if (!HasFlagEnum)
678689
setFlagEnum(RHS.isFlagEnum());
679690

@@ -690,6 +701,9 @@ class TagInfo : public CommonTypeInfo {
690701

691702
inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
692703
return static_cast<const CommonTypeInfo &>(LHS) == RHS &&
704+
LHS.SwiftImportAs == RHS.SwiftImportAs &&
705+
LHS.SwiftRetainOp == RHS.SwiftRetainOp &&
706+
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp &&
693707
LHS.isFlagEnum() == RHS.isFlagEnum() &&
694708
LHS.EnumExtensibility == RHS.EnumExtensibility;
695709
}

clang/lib/APINotes/APINotesFormat.h

Lines changed: 1 addition & 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; // SwiftImportAs
2727

2828
using IdentifierID = llvm::PointerEmbeddedInt<unsigned, 31>;
2929
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: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,12 +1109,15 @@ namespace {
11091109
}
11101110
};
11111111

1112-
/// Used to serialize the on-disk tag table.
1113-
class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
1114-
public:
1115-
unsigned getUnversionedInfoSize(const TagInfo &info) {
1116-
return 1 + getCommonTypeInfoSize(info);
1117-
}
1112+
/// Used to serialize the on-disk tag table.
1113+
class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
1114+
public:
1115+
unsigned getUnversionedInfoSize(const TagInfo &TI) {
1116+
return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
1117+
2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
1118+
2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
1119+
1 + getCommonTypeInfoSize(TI);
1120+
}
11181121

11191122
void emitUnversionedInfo(raw_ostream &out, const TagInfo &info) {
11201123
endian::Writer writer(out, little);
@@ -1133,11 +1136,29 @@ namespace {
11331136

11341137
writer.write<uint8_t>(payload);
11351138

1136-
emitCommonTypeInfo(out, info);
1139+
if (auto ImportAs = info.SwiftImportAs) {
1140+
writer.write<uint16_t>(ImportAs->size() + 1);
1141+
out.write(ImportAs->c_str(), ImportAs->size());
1142+
} else {
1143+
writer.write<uint16_t>(0);
1144+
}
1145+
if (auto RetainOp = info.SwiftRetainOp) {
1146+
writer.write<uint16_t>(RetainOp->size() + 1);
1147+
out.write(RetainOp->c_str(), RetainOp->size());
1148+
} else {
1149+
writer.write<uint16_t>(0);
1150+
}
1151+
if (auto ReleaseOp = info.SwiftReleaseOp) {
1152+
writer.write<uint16_t>(ReleaseOp->size() + 1);
1153+
out.write(ReleaseOp->c_str(), ReleaseOp->size());
1154+
} else {
1155+
writer.write<uint16_t>(0);
11371156
}
1138-
};
11391157

1140-
} // end anonymous namespace
1158+
emitCommonTypeInfo(out, info);
1159+
}
1160+
};
1161+
} // namespace
11411162

11421163
void APINotesWriter::Implementation::writeTagBlock(
11431164
llvm::BitstreamWriter &writer) {

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
Optional<bool> SwiftPrivate;
528528
Optional<StringRef> SwiftBridge;
529529
Optional<StringRef> NSErrorDomain;
530+
Optional<std::string> SwiftImportAs;
531+
Optional<std::string> SwiftRetainOp;
532+
Optional<std::string> SwiftReleaseOp;
530533
Optional<EnumExtensibilityKind> EnumExtensibility;
531534
Optional<bool> FlagEnum;
532535
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);
@@ -1130,6 +1136,27 @@ namespace {
11301136
if (convertCommonType(t, tagInfo, t.Name))
11311137
continue;
11321138

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

clang/lib/Sema/SemaAPINotes.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,22 @@ static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D,
627627
static void ProcessAPINotes(Sema &S, TagDecl *D,
628628
const api_notes::TagInfo &info,
629629
VersionedInfoMetadata metadata) {
630+
if (auto ImportAs = info.SwiftImportAs) {
631+
auto str = "import_" + ImportAs.value();
632+
auto attr = SwiftAttrAttr::Create(S.Context, str, AttributeCommonInfo(clang::SourceRange()));
633+
D->addAttr(attr);
634+
}
635+
if (auto RetainOp = info.SwiftRetainOp) {
636+
auto str = "retain:" + RetainOp.value();
637+
auto attr = SwiftAttrAttr::Create(S.Context, str, AttributeCommonInfo(clang::SourceRange()));
638+
D->addAttr(attr);
639+
}
640+
if (auto ReleaseOp = info.SwiftReleaseOp) {
641+
auto str = "release:" + ReleaseOp.value();
642+
auto attr = SwiftAttrAttr::Create(S.Context, str, AttributeCommonInfo(clang::SourceRange()));
643+
D->addAttr(attr);
644+
}
645+
630646
if (auto extensibility = info.EnumExtensibility) {
631647
using api_notes::EnumExtensibilityKind;
632648
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)