Skip to content

Commit cdedc81

Browse files
authored
[APINotes] Support annotating safety of APIs (#157506)
1 parent e1d60f7 commit cdedc81

File tree

11 files changed

+190
-8
lines changed

11 files changed

+190
-8
lines changed

clang/docs/APINotes.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,20 @@ declaration kind), all of which are optional:
229229
- Name: vector
230230
SwiftConformsTo: Cxx.CxxSequence
231231

232+
:SwiftSafety:
233+
234+
Import a declaration as ``@safe`` or ``@unsafe`` to Swift.
235+
236+
::
237+
238+
Tags:
239+
- Name: UnsafeType
240+
SwiftSafety: unsafe
241+
- Name: span
242+
Methods:
243+
- Name: size
244+
SwiftSafety: safe
245+
232246
:Availability, AvailabilityMsg:
233247

234248
A value of "nonswift" is equivalent to ``NS_SWIFT_UNAVAILABLE``. A value of

clang/include/clang/APINotes/Types.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ enum class SwiftNewTypeKind {
4646
Enum,
4747
};
4848

49+
enum class SwiftSafetyKind { Unspecified, Safe, Unsafe, None };
50+
4951
/// Describes API notes data for any entity.
5052
///
5153
/// This is used as the base of all API notes.
@@ -71,13 +73,19 @@ class CommonEntityInfo {
7173
LLVM_PREFERRED_TYPE(bool)
7274
unsigned SwiftPrivate : 1;
7375

76+
LLVM_PREFERRED_TYPE(bool)
77+
unsigned SwiftSafetyAudited : 1;
78+
79+
LLVM_PREFERRED_TYPE(SwiftSafetyKind)
80+
unsigned SwiftSafety : 2;
81+
7482
public:
7583
/// Swift name of this entity.
7684
std::string SwiftName;
7785

7886
CommonEntityInfo()
7987
: Unavailable(0), UnavailableInSwift(0), SwiftPrivateSpecified(0),
80-
SwiftPrivate(0) {}
88+
SwiftPrivate(0), SwiftSafetyAudited(0), SwiftSafety(0) {}
8189

8290
std::optional<bool> isSwiftPrivate() const {
8391
return SwiftPrivateSpecified ? std::optional<bool>(SwiftPrivate)
@@ -89,6 +97,17 @@ class CommonEntityInfo {
8997
SwiftPrivate = Private.value_or(0);
9098
}
9199

100+
std::optional<SwiftSafetyKind> getSwiftSafety() const {
101+
return SwiftSafetyAudited ? std::optional<SwiftSafetyKind>(
102+
static_cast<SwiftSafetyKind>(SwiftSafety))
103+
: std::nullopt;
104+
}
105+
106+
void setSwiftSafety(SwiftSafetyKind Safety) {
107+
SwiftSafetyAudited = 1;
108+
SwiftSafety = static_cast<unsigned>(Safety);
109+
}
110+
92111
friend bool operator==(const CommonEntityInfo &, const CommonEntityInfo &);
93112

94113
CommonEntityInfo &operator|=(const CommonEntityInfo &RHS) {
@@ -108,6 +127,9 @@ class CommonEntityInfo {
108127
if (!SwiftPrivateSpecified)
109128
setSwiftPrivate(RHS.isSwiftPrivate());
110129

130+
if (!SwiftSafetyAudited && RHS.SwiftSafetyAudited)
131+
setSwiftSafety(*RHS.getSwiftSafety());
132+
111133
if (SwiftName.empty())
112134
SwiftName = RHS.SwiftName;
113135

@@ -123,7 +145,9 @@ inline bool operator==(const CommonEntityInfo &LHS,
123145
LHS.Unavailable == RHS.Unavailable &&
124146
LHS.UnavailableInSwift == RHS.UnavailableInSwift &&
125147
LHS.SwiftPrivateSpecified == RHS.SwiftPrivateSpecified &&
126-
LHS.SwiftPrivate == RHS.SwiftPrivate && LHS.SwiftName == RHS.SwiftName;
148+
LHS.SwiftPrivate == RHS.SwiftPrivate &&
149+
LHS.SwiftSafetyAudited == RHS.SwiftSafetyAudited &&
150+
LHS.SwiftSafety == RHS.SwiftSafety && LHS.SwiftName == RHS.SwiftName;
127151
}
128152

129153
inline bool operator!=(const CommonEntityInfo &LHS,

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 = 37; // SwiftDestroyOp
27+
const uint16_t VERSION_MINOR = 38; // SwiftSafety
2828

2929
const uint8_t kSwiftConforms = 1;
3030
const uint8_t kSwiftDoesNotConform = 2;

clang/lib/APINotes/APINotesReader.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,14 @@ class VersionedTableInfo {
9494

9595
/// Read serialized CommonEntityInfo.
9696
void ReadCommonEntityInfo(const uint8_t *&Data, CommonEntityInfo &Info) {
97-
uint8_t UnavailableBits = *Data++;
98-
Info.Unavailable = (UnavailableBits >> 1) & 0x01;
99-
Info.UnavailableInSwift = UnavailableBits & 0x01;
100-
if ((UnavailableBits >> 2) & 0x01)
101-
Info.setSwiftPrivate(static_cast<bool>((UnavailableBits >> 3) & 0x01));
97+
uint8_t EncodedBits = *Data++;
98+
Info.Unavailable = (EncodedBits >> 1) & 0x01;
99+
Info.UnavailableInSwift = EncodedBits & 0x01;
100+
if ((EncodedBits >> 2) & 0x01)
101+
Info.setSwiftPrivate(static_cast<bool>((EncodedBits >> 3) & 0x01));
102+
if ((EncodedBits >> 4) & 0x01)
103+
Info.setSwiftSafety(
104+
static_cast<SwiftSafetyKind>((EncodedBits >> 5) & 0x03));
102105

103106
unsigned MsgLength =
104107
endian::readNext<uint16_t, llvm::endianness::little>(Data);

clang/lib/APINotes/APINotesTypes.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@ LLVM_DUMP_METHOD void CommonEntityInfo::dump(llvm::raw_ostream &OS) const {
1818
OS << "[UnavailableInSwift] ";
1919
if (SwiftPrivateSpecified)
2020
OS << (SwiftPrivate ? "[SwiftPrivate] " : "");
21+
if (SwiftSafetyAudited) {
22+
switch (*getSwiftSafety()) {
23+
case SwiftSafetyKind::Safe:
24+
OS << "[Safe] ";
25+
break;
26+
case SwiftSafetyKind::Unsafe:
27+
OS << "[Unsafe] ";
28+
break;
29+
case SwiftSafetyKind::Unspecified:
30+
OS << "[Unspecified] ";
31+
break;
32+
case SwiftSafetyKind::None:
33+
break;
34+
}
35+
}
2136
if (!SwiftName.empty())
2237
OS << "Swift Name: " << SwiftName << ' ';
2338
OS << '\n';

clang/lib/APINotes/APINotesWriter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,12 @@ void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
507507
llvm::support::endian::Writer writer(OS, llvm::endianness::little);
508508

509509
uint8_t payload = 0;
510+
if (auto safety = CEI.getSwiftSafety()) {
511+
payload = static_cast<unsigned>(*safety);
512+
payload <<= 1;
513+
payload |= 0x01;
514+
}
515+
payload <<= 2;
510516
if (auto swiftPrivate = CEI.isSwiftPrivate()) {
511517
payload |= 0x01;
512518
if (*swiftPrivate)

clang/lib/APINotes/APINotesYAMLCompiler.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@
2929
using namespace clang;
3030
using namespace api_notes;
3131

32+
namespace llvm {
33+
namespace yaml {
34+
template <> struct ScalarEnumerationTraits<SwiftSafetyKind> {
35+
static void enumeration(IO &IO, SwiftSafetyKind &SK) {
36+
IO.enumCase(SK, "unspecified", SwiftSafetyKind::Unspecified);
37+
IO.enumCase(SK, "safe", SwiftSafetyKind::Safe);
38+
IO.enumCase(SK, "unsafe", SwiftSafetyKind::Unsafe);
39+
}
40+
};
41+
} // namespace yaml
42+
} // namespace llvm
43+
3244
namespace {
3345
enum class APIAvailability {
3446
Available = 0,
@@ -163,6 +175,7 @@ struct Method {
163175
bool Required = false;
164176
StringRef ResultType;
165177
StringRef SwiftReturnOwnership;
178+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
166179
};
167180

168181
typedef std::vector<Method> MethodsSeq;
@@ -199,6 +212,7 @@ template <> struct MappingTraits<Method> {
199212
IO.mapOptional("ResultType", M.ResultType, StringRef(""));
200213
IO.mapOptional("SwiftReturnOwnership", M.SwiftReturnOwnership,
201214
StringRef(""));
215+
IO.mapOptional("SwiftSafety", M.SafetyKind, SwiftSafetyKind::None);
202216
}
203217
};
204218
} // namespace yaml
@@ -214,6 +228,7 @@ struct Property {
214228
StringRef SwiftName;
215229
std::optional<bool> SwiftImportAsAccessors;
216230
StringRef Type;
231+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
217232
};
218233

219234
typedef std::vector<Property> PropertiesSeq;
@@ -235,6 +250,7 @@ template <> struct MappingTraits<Property> {
235250
IO.mapOptional("SwiftName", P.SwiftName, StringRef(""));
236251
IO.mapOptional("SwiftImportAsAccessors", P.SwiftImportAsAccessors);
237252
IO.mapOptional("Type", P.Type, StringRef(""));
253+
IO.mapOptional("SwiftSafety", P.SafetyKind, SwiftSafetyKind::None);
238254
}
239255
};
240256
} // namespace yaml
@@ -254,6 +270,7 @@ struct Class {
254270
std::optional<std::string> SwiftConformance;
255271
MethodsSeq Methods;
256272
PropertiesSeq Properties;
273+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
257274
};
258275

259276
typedef std::vector<Class> ClassesSeq;
@@ -279,6 +296,7 @@ template <> struct MappingTraits<Class> {
279296
IO.mapOptional("SwiftConformsTo", C.SwiftConformance);
280297
IO.mapOptional("Methods", C.Methods);
281298
IO.mapOptional("Properties", C.Properties);
299+
IO.mapOptional("SwiftSafety", C.SafetyKind, SwiftSafetyKind::None);
282300
}
283301
};
284302
} // namespace yaml
@@ -297,6 +315,7 @@ struct Function {
297315
StringRef Type;
298316
StringRef ResultType;
299317
StringRef SwiftReturnOwnership;
318+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
300319
};
301320

302321
typedef std::vector<Function> FunctionsSeq;
@@ -321,6 +340,7 @@ template <> struct MappingTraits<Function> {
321340
IO.mapOptional("ResultType", F.ResultType, StringRef(""));
322341
IO.mapOptional("SwiftReturnOwnership", F.SwiftReturnOwnership,
323342
StringRef(""));
343+
IO.mapOptional("SwiftSafety", F.SafetyKind, SwiftSafetyKind::None);
324344
}
325345
};
326346
} // namespace yaml
@@ -334,6 +354,7 @@ struct GlobalVariable {
334354
std::optional<bool> SwiftPrivate;
335355
StringRef SwiftName;
336356
StringRef Type;
357+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
337358
};
338359

339360
typedef std::vector<GlobalVariable> GlobalVariablesSeq;
@@ -353,6 +374,7 @@ template <> struct MappingTraits<GlobalVariable> {
353374
IO.mapOptional("SwiftPrivate", GV.SwiftPrivate);
354375
IO.mapOptional("SwiftName", GV.SwiftName, StringRef(""));
355376
IO.mapOptional("Type", GV.Type, StringRef(""));
377+
IO.mapOptional("SwiftSafety", GV.SafetyKind, SwiftSafetyKind::None);
356378
}
357379
};
358380
} // namespace yaml
@@ -364,6 +386,7 @@ struct EnumConstant {
364386
AvailabilityItem Availability;
365387
std::optional<bool> SwiftPrivate;
366388
StringRef SwiftName;
389+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
367390
};
368391

369392
typedef std::vector<EnumConstant> EnumConstantsSeq;
@@ -381,6 +404,7 @@ template <> struct MappingTraits<EnumConstant> {
381404
IO.mapOptional("AvailabilityMsg", EC.Availability.Msg, StringRef(""));
382405
IO.mapOptional("SwiftPrivate", EC.SwiftPrivate);
383406
IO.mapOptional("SwiftName", EC.SwiftName, StringRef(""));
407+
IO.mapOptional("SwiftSafety", EC.SafetyKind, SwiftSafetyKind::None);
384408
}
385409
};
386410
} // namespace yaml
@@ -424,6 +448,7 @@ struct Field {
424448
std::optional<bool> SwiftPrivate;
425449
StringRef SwiftName;
426450
StringRef Type;
451+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
427452
};
428453

429454
typedef std::vector<Field> FieldsSeq;
@@ -443,6 +468,7 @@ template <> struct MappingTraits<Field> {
443468
IO.mapOptional("SwiftPrivate", F.SwiftPrivate);
444469
IO.mapOptional("SwiftName", F.SwiftName, StringRef(""));
445470
IO.mapOptional("Type", F.Type, StringRef(""));
471+
IO.mapOptional("SwiftSafety", F.SafetyKind, SwiftSafetyKind::None);
446472
}
447473
};
448474
} // namespace yaml
@@ -470,6 +496,7 @@ struct Tag {
470496
std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
471497
std::optional<bool> SwiftCopyable;
472498
std::optional<bool> SwiftEscapable;
499+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
473500
FunctionsSeq Methods;
474501
FieldsSeq Fields;
475502

@@ -515,6 +542,7 @@ template <> struct MappingTraits<Tag> {
515542
IO.mapOptional("Methods", T.Methods);
516543
IO.mapOptional("Fields", T.Fields);
517544
IO.mapOptional("Tags", T.Tags);
545+
IO.mapOptional("SwiftSafety", T.SafetyKind, SwiftSafetyKind::None);
518546
}
519547
};
520548
} // namespace yaml
@@ -530,6 +558,7 @@ struct Typedef {
530558
std::optional<StringRef> NSErrorDomain;
531559
std::optional<SwiftNewTypeKind> SwiftType;
532560
std::optional<std::string> SwiftConformance;
561+
const SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
533562
};
534563

535564
typedef std::vector<Typedef> TypedefsSeq;
@@ -602,6 +631,7 @@ struct Namespace {
602631
StringRef SwiftName;
603632
std::optional<bool> SwiftPrivate;
604633
TopLevelItems Items;
634+
const SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
605635
};
606636
} // namespace
607637

@@ -797,6 +827,8 @@ class YAMLConverter {
797827
StringRef APIName) {
798828
convertAvailability(Common.Availability, Info, APIName);
799829
Info.setSwiftPrivate(Common.SwiftPrivate);
830+
if (Common.SafetyKind != SwiftSafetyKind::None)
831+
Info.setSwiftSafety(Common.SafetyKind);
800832
Info.SwiftName = std::string(Common.SwiftName);
801833
}
802834

@@ -956,6 +988,8 @@ class YAMLConverter {
956988
void convertFunction(const Function &Function, FuncOrMethodInfo &FI) {
957989
convertAvailability(Function.Availability, FI, Function.Name);
958990
FI.setSwiftPrivate(Function.SwiftPrivate);
991+
if (Function.SafetyKind != SwiftSafetyKind::None)
992+
FI.setSwiftSafety(Function.SafetyKind);
959993
FI.SwiftName = std::string(Function.SwiftName);
960994
std::optional<ParamInfo> This;
961995
convertParams(Function.Params, FI, This);

clang/lib/Sema/SemaAPINotes.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "CheckExprLifetime.h"
1414
#include "TypeLocBuilder.h"
1515
#include "clang/APINotes/APINotesReader.h"
16+
#include "clang/APINotes/Types.h"
1617
#include "clang/AST/Decl.h"
1718
#include "clang/AST/DeclCXX.h"
1819
#include "clang/AST/DeclObjC.h"
@@ -291,6 +292,29 @@ static void ProcessAPINotes(Sema &S, Decl *D,
291292
});
292293
}
293294

295+
// swift_safety
296+
if (auto SafetyKind = Info.getSwiftSafety()) {
297+
bool Addition = *SafetyKind != api_notes::SwiftSafetyKind::Unspecified;
298+
handleAPINotedAttribute<SwiftAttrAttr>(
299+
S, D, Addition, Metadata,
300+
[&] {
301+
return SwiftAttrAttr::Create(
302+
S.Context, *SafetyKind == api_notes::SwiftSafetyKind::Safe
303+
? "safe"
304+
: "unsafe");
305+
},
306+
[](const Decl *D) {
307+
return llvm::find_if(D->attrs(), [](const Attr *attr) {
308+
if (const auto *swiftAttr = dyn_cast<SwiftAttrAttr>(attr)) {
309+
if (swiftAttr->getAttribute() == "safe" ||
310+
swiftAttr->getAttribute() == "unsafe")
311+
return true;
312+
}
313+
return false;
314+
});
315+
});
316+
}
317+
294318
// swift_name
295319
if (!Info.SwiftName.empty()) {
296320
handleAPINotedAttribute<SwiftNameAttr>(

0 commit comments

Comments
 (0)