Skip to content

Commit fa31170

Browse files
authored
Merge pull request #8671 from apple/egorzhdan/20240408-apinotes-noncopyable
🍒[APINotes] Allow annotating a C++ type as non-copyable in Swift
2 parents db53966 + 83b7524 commit fa31170

File tree

9 files changed

+65
-3
lines changed

9 files changed

+65
-3
lines changed

clang/include/clang/APINotes/Types.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,14 +678,21 @@ class TagInfo : public CommonTypeInfo {
678678
LLVM_PREFERRED_TYPE(bool)
679679
unsigned IsFlagEnum : 1;
680680

681+
LLVM_PREFERRED_TYPE(bool)
682+
unsigned SwiftCopyableSpecified : 1;
683+
LLVM_PREFERRED_TYPE(bool)
684+
unsigned SwiftCopyable : 1;
685+
681686
public:
682687
std::optional<std::string> SwiftImportAs;
683688
std::optional<std::string> SwiftRetainOp;
684689
std::optional<std::string> SwiftReleaseOp;
685690

686691
std::optional<EnumExtensibilityKind> EnumExtensibility;
687692

688-
TagInfo() : HasFlagEnum(0), IsFlagEnum(0) {}
693+
TagInfo()
694+
: HasFlagEnum(0), IsFlagEnum(0), SwiftCopyableSpecified(false),
695+
SwiftCopyable(false) {}
689696

690697
std::optional<bool> isFlagEnum() const {
691698
if (HasFlagEnum)
@@ -697,6 +704,15 @@ class TagInfo : public CommonTypeInfo {
697704
IsFlagEnum = Value.value_or(false);
698705
}
699706

707+
std::optional<bool> isSwiftCopyable() const {
708+
return SwiftCopyableSpecified ? std::optional<bool>(SwiftCopyable)
709+
: std::nullopt;
710+
}
711+
void setSwiftCopyable(std::optional<bool> Value) {
712+
SwiftCopyableSpecified = Value.has_value();
713+
SwiftCopyable = Value.value_or(false);
714+
}
715+
700716
TagInfo &operator|=(const TagInfo &RHS) {
701717
static_cast<CommonTypeInfo &>(*this) |= RHS;
702718

@@ -713,6 +729,9 @@ class TagInfo : public CommonTypeInfo {
713729
if (!EnumExtensibility)
714730
EnumExtensibility = RHS.EnumExtensibility;
715731

732+
if (!SwiftCopyableSpecified)
733+
setSwiftCopyable(RHS.isSwiftCopyable());
734+
716735
return *this;
717736
}
718737

@@ -727,6 +746,7 @@ inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
727746
LHS.SwiftRetainOp == RHS.SwiftRetainOp &&
728747
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp &&
729748
LHS.isFlagEnum() == RHS.isFlagEnum() &&
749+
LHS.isSwiftCopyable() == RHS.isSwiftCopyable() &&
730750
LHS.EnumExtensibility == RHS.EnumExtensibility;
731751
}
732752

clang/lib/APINotes/APINotesFormat.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ 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 = 25; // SwiftImportAs
27+
const uint16_t VERSION_MINOR = 26; // SwiftCopyable
28+
29+
const uint8_t kSwiftCopyable = 1;
30+
const uint8_t kSwiftNonCopyable = 2;
2831

2932
using IdentifierID = llvm::PointerEmbeddedInt<unsigned, 31>;
3033
using IdentifierIDField = llvm::BCVBR<16>;

clang/lib/APINotes/APINotesReader.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,13 @@ class TagTableInfo
552552
Info.EnumExtensibility =
553553
static_cast<EnumExtensibilityKind>((Payload & 0x3) - 1);
554554

555+
uint8_t Copyable =
556+
endian::readNext<uint8_t, llvm::endianness::little, unaligned>(Data);
557+
if (Copyable == kSwiftNonCopyable)
558+
Info.setSwiftCopyable(std::optional(false));
559+
else if (Copyable == kSwiftCopyable)
560+
Info.setSwiftCopyable(std::optional(true));
561+
555562
unsigned ImportAsLength =
556563
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(Data);
557564
if (ImportAsLength > 0) {

clang/lib/APINotes/APINotesWriter.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
11351135
return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
11361136
2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
11371137
2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
1138-
1 + getCommonTypeInfoSize(TI);
1138+
2 + getCommonTypeInfoSize(TI);
11391139
}
11401140

11411141
void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
@@ -1153,6 +1153,11 @@ class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
11531153

11541154
writer.write<uint8_t>(Flags);
11551155

1156+
if (auto Copyable = TI.isSwiftCopyable())
1157+
writer.write<uint8_t>(*Copyable ? kSwiftCopyable : kSwiftNonCopyable);
1158+
else
1159+
writer.write<uint8_t>(0);
1160+
11561161
if (auto ImportAs = TI.SwiftImportAs) {
11571162
writer.write<uint16_t>(ImportAs->size() + 1);
11581163
OS.write(ImportAs->c_str(), ImportAs->size());

clang/lib/APINotes/APINotesYAMLCompiler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ struct Tag {
532532
std::optional<EnumExtensibilityKind> EnumExtensibility;
533533
std::optional<bool> FlagEnum;
534534
std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
535+
std::optional<bool> SwiftCopyable;
535536
};
536537

537538
typedef std::vector<Tag> TagsSeq;
@@ -565,6 +566,7 @@ template <> struct MappingTraits<Tag> {
565566
IO.mapOptional("EnumExtensibility", T.EnumExtensibility);
566567
IO.mapOptional("FlagEnum", T.FlagEnum);
567568
IO.mapOptional("EnumKind", T.EnumConvenienceKind);
569+
IO.mapOptional("SwiftCopyable", T.SwiftCopyable);
568570
}
569571
};
570572
} // namespace yaml
@@ -1122,6 +1124,9 @@ class YAMLConverter {
11221124
if (Tag.SwiftReleaseOp)
11231125
TI.SwiftReleaseOp = Tag.SwiftReleaseOp;
11241126

1127+
if (Tag.SwiftCopyable)
1128+
TI.setSwiftCopyable(Tag.SwiftCopyable);
1129+
11251130
if (Tag.EnumConvenienceKind) {
11261131
if (Tag.EnumExtensibility) {
11271132
emitError(

clang/lib/Sema/SemaAPINotes.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,11 @@ static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,
592592
D->addAttr(
593593
SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value()));
594594

595+
if (auto Copyable = Info.isSwiftCopyable()) {
596+
if (!*Copyable)
597+
D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable"));
598+
}
599+
595600
if (auto Extensibility = Info.EnumExtensibility) {
596601
using api_notes::EnumExtensibilityKind;
597602
bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None);

clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ Tags:
77
SwiftImportAs: reference
88
SwiftReleaseOp: RCRelease
99
SwiftRetainOp: RCRetain
10+
- Name: NonCopyableType
11+
SwiftCopyable: false
12+
- Name: CopyableType
13+
SwiftCopyable: true

clang/test/APINotes/Inputs/Headers/SwiftImportAs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ struct RefCountedType { int value; };
44

55
inline void RCRetain(RefCountedType *x) { x->value++; }
66
inline void RCRelease(RefCountedType *x) { x->value--; }
7+
8+
struct NonCopyableType { int value; };
9+
struct CopyableType { int value; };

clang/test/APINotes/swift-import-as.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// 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++
33
// 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
44
// 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+
// 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 NonCopyableType | FileCheck -check-prefix=CHECK-NON-COPYABLE %s
6+
// 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 CopyableType | FileCheck -check-prefix=CHECK-COPYABLE %s
57

68
#include <SwiftImportAs.h>
79

@@ -14,3 +16,11 @@
1416
// CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "import_reference"
1517
// CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "retain:RCRetain"
1618
// CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "release:RCRelease"
19+
20+
// CHECK-NON-COPYABLE: Dumping NonCopyableType:
21+
// CHECK-NON-COPYABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct NonCopyableType
22+
// CHECK-NON-COPYABLE: SwiftAttrAttr {{.+}} <<invalid sloc>> "~Copyable"
23+
24+
// CHECK-COPYABLE: Dumping CopyableType:
25+
// CHECK-COPYABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct CopyableType
26+
// CHECK-COPYABLE-NOT: SwiftAttrAttr

0 commit comments

Comments
 (0)