Skip to content

Commit f7313f7

Browse files
Xazax-hunGabor Horvath
authored andcommitted
[APINotes] Support annotating safety of APIs (llvm#157506)
1 parent 68128bc commit f7313f7

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
@@ -211,6 +211,20 @@ declaration kind), all of which are optional:
211211
- Name: vector
212212
SwiftConformsTo: Cxx.CxxSequence
213213

214+
:SwiftSafety:
215+
216+
Import a declaration as ``@safe`` or ``@unsafe`` to Swift.
217+
218+
::
219+
220+
Tags:
221+
- Name: UnsafeType
222+
SwiftSafety: unsafe
223+
- Name: span
224+
Methods:
225+
- Name: size
226+
SwiftSafety: safe
227+
214228
:Availability, AvailabilityMsg:
215229

216230
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 = 39; // SwiftSafety (38) and TO_UPSTREAM(BoundsSafety) (39)
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
@@ -96,11 +96,14 @@ class VersionedTableInfo {
9696

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

105108
unsigned MsgLength =
106109
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
@@ -524,6 +524,12 @@ void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
524524
llvm::support::endian::Writer writer(OS, llvm::endianness::little);
525525

526526
uint8_t payload = 0;
527+
if (auto safety = CEI.getSwiftSafety()) {
528+
payload = static_cast<unsigned>(*safety);
529+
payload <<= 1;
530+
payload |= 0x01;
531+
}
532+
payload <<= 2;
527533
if (auto swiftPrivate = CEI.isSwiftPrivate()) {
528534
payload |= 0x01;
529535
if (*swiftPrivate)

clang/lib/APINotes/APINotesYAMLCompiler.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,18 @@ Each global variable definition is of the following form:
141141
AvailabilityMsg: ""
142142
143143
*/
144+
namespace llvm {
145+
146+
namespace yaml {
147+
template <> struct ScalarEnumerationTraits<SwiftSafetyKind> {
148+
static void enumeration(IO &IO, SwiftSafetyKind &SK) {
149+
IO.enumCase(SK, "unspecified", SwiftSafetyKind::Unspecified);
150+
IO.enumCase(SK, "safe", SwiftSafetyKind::Safe);
151+
IO.enumCase(SK, "unsafe", SwiftSafetyKind::Unsafe);
152+
}
153+
};
154+
} // namespace yaml
155+
} // namespace llvm
144156

145157
namespace {
146158
enum class APIAvailability {
@@ -322,6 +334,7 @@ struct Method {
322334
/* TO_UPSTREAM(BoundsSafety) ON */
323335
std::optional<BoundsSafetyNotes> ReturnBoundsSafety;
324336
/* TO_UPSTREAM(BoundsSafety) OFF */
337+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
325338
};
326339

327340
typedef std::vector<Method> MethodsSeq;
@@ -361,6 +374,7 @@ template <> struct MappingTraits<Method> {
361374
/* TO_UPSTREAM(BoundsSafety) ON */
362375
IO.mapOptional("BoundsSafety", M.ReturnBoundsSafety);
363376
/* TO_UPSTREAM(BoundsSafety) OFF */
377+
IO.mapOptional("SwiftSafety", M.SafetyKind, SwiftSafetyKind::None);
364378
}
365379
};
366380
} // namespace yaml
@@ -376,6 +390,7 @@ struct Property {
376390
StringRef SwiftName;
377391
std::optional<bool> SwiftImportAsAccessors;
378392
StringRef Type;
393+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
379394
};
380395

381396
typedef std::vector<Property> PropertiesSeq;
@@ -397,6 +412,7 @@ template <> struct MappingTraits<Property> {
397412
IO.mapOptional("SwiftName", P.SwiftName, StringRef(""));
398413
IO.mapOptional("SwiftImportAsAccessors", P.SwiftImportAsAccessors);
399414
IO.mapOptional("Type", P.Type, StringRef(""));
415+
IO.mapOptional("SwiftSafety", P.SafetyKind, SwiftSafetyKind::None);
400416
}
401417
};
402418
} // namespace yaml
@@ -416,6 +432,7 @@ struct Class {
416432
std::optional<std::string> SwiftConformance;
417433
MethodsSeq Methods;
418434
PropertiesSeq Properties;
435+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
419436
};
420437

421438
typedef std::vector<Class> ClassesSeq;
@@ -441,6 +458,7 @@ template <> struct MappingTraits<Class> {
441458
IO.mapOptional("SwiftConformsTo", C.SwiftConformance);
442459
IO.mapOptional("Methods", C.Methods);
443460
IO.mapOptional("Properties", C.Properties);
461+
IO.mapOptional("SwiftSafety", C.SafetyKind, SwiftSafetyKind::None);
444462
}
445463
};
446464
} // namespace yaml
@@ -462,6 +480,7 @@ struct Function {
462480
/* TO_UPSTREAM(BoundsSafety) ON */
463481
std::optional<BoundsSafetyNotes> ReturnBoundsSafety;
464482
/* TO_UPSTREAM(BoundsSafety) OFF */
483+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
465484
};
466485

467486
typedef std::vector<Function> FunctionsSeq;
@@ -489,6 +508,7 @@ template <> struct MappingTraits<Function> {
489508
/* TO_UPSTREAM(BoundsSafety) ON */
490509
IO.mapOptional("BoundsSafety", F.ReturnBoundsSafety);
491510
/* TO_UPSTREAM(BoundsSafety) OFF */
511+
IO.mapOptional("SwiftSafety", F.SafetyKind, SwiftSafetyKind::None);
492512
}
493513
};
494514
} // namespace yaml
@@ -502,6 +522,7 @@ struct GlobalVariable {
502522
std::optional<bool> SwiftPrivate;
503523
StringRef SwiftName;
504524
StringRef Type;
525+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
505526
};
506527

507528
typedef std::vector<GlobalVariable> GlobalVariablesSeq;
@@ -521,6 +542,7 @@ template <> struct MappingTraits<GlobalVariable> {
521542
IO.mapOptional("SwiftPrivate", GV.SwiftPrivate);
522543
IO.mapOptional("SwiftName", GV.SwiftName, StringRef(""));
523544
IO.mapOptional("Type", GV.Type, StringRef(""));
545+
IO.mapOptional("SwiftSafety", GV.SafetyKind, SwiftSafetyKind::None);
524546
}
525547
};
526548
} // namespace yaml
@@ -532,6 +554,7 @@ struct EnumConstant {
532554
AvailabilityItem Availability;
533555
std::optional<bool> SwiftPrivate;
534556
StringRef SwiftName;
557+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
535558
};
536559

537560
typedef std::vector<EnumConstant> EnumConstantsSeq;
@@ -549,6 +572,7 @@ template <> struct MappingTraits<EnumConstant> {
549572
IO.mapOptional("AvailabilityMsg", EC.Availability.Msg, StringRef(""));
550573
IO.mapOptional("SwiftPrivate", EC.SwiftPrivate);
551574
IO.mapOptional("SwiftName", EC.SwiftName, StringRef(""));
575+
IO.mapOptional("SwiftSafety", EC.SafetyKind, SwiftSafetyKind::None);
552576
}
553577
};
554578
} // namespace yaml
@@ -592,6 +616,7 @@ struct Field {
592616
std::optional<bool> SwiftPrivate;
593617
StringRef SwiftName;
594618
StringRef Type;
619+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
595620
};
596621

597622
typedef std::vector<Field> FieldsSeq;
@@ -611,6 +636,7 @@ template <> struct MappingTraits<Field> {
611636
IO.mapOptional("SwiftPrivate", F.SwiftPrivate);
612637
IO.mapOptional("SwiftName", F.SwiftName, StringRef(""));
613638
IO.mapOptional("Type", F.Type, StringRef(""));
639+
IO.mapOptional("SwiftSafety", F.SafetyKind, SwiftSafetyKind::None);
614640
}
615641
};
616642
} // namespace yaml
@@ -637,6 +663,7 @@ struct Tag {
637663
std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
638664
std::optional<bool> SwiftCopyable;
639665
std::optional<bool> SwiftEscapable;
666+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
640667
FunctionsSeq Methods;
641668
FieldsSeq Fields;
642669

@@ -681,6 +708,7 @@ template <> struct MappingTraits<Tag> {
681708
IO.mapOptional("Methods", T.Methods);
682709
IO.mapOptional("Fields", T.Fields);
683710
IO.mapOptional("Tags", T.Tags);
711+
IO.mapOptional("SwiftSafety", T.SafetyKind, SwiftSafetyKind::None);
684712
}
685713
};
686714
} // namespace yaml
@@ -696,6 +724,7 @@ struct Typedef {
696724
std::optional<StringRef> NSErrorDomain;
697725
std::optional<SwiftNewTypeKind> SwiftType;
698726
std::optional<std::string> SwiftConformance;
727+
const SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
699728
};
700729

701730
typedef std::vector<Typedef> TypedefsSeq;
@@ -768,6 +797,7 @@ struct Namespace {
768797
StringRef SwiftName;
769798
std::optional<bool> SwiftPrivate;
770799
TopLevelItems Items;
800+
const SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
771801
};
772802
} // namespace
773803

@@ -972,6 +1002,8 @@ class YAMLConverter {
9721002
StringRef APIName) {
9731003
convertAvailability(Common.Availability, Info, APIName);
9741004
Info.setSwiftPrivate(Common.SwiftPrivate);
1005+
if (Common.SafetyKind != SwiftSafetyKind::None)
1006+
Info.setSwiftSafety(Common.SafetyKind);
9751007
Info.SwiftName = std::string(Common.SwiftName);
9761008
}
9771009

@@ -1131,6 +1163,8 @@ class YAMLConverter {
11311163
void convertFunction(const Function &Function, FuncOrMethodInfo &FI) {
11321164
convertAvailability(Function.Availability, FI, Function.Name);
11331165
FI.setSwiftPrivate(Function.SwiftPrivate);
1166+
if (Function.SafetyKind != SwiftSafetyKind::None)
1167+
FI.setSwiftSafety(Function.SafetyKind);
11341168
FI.SwiftName = std::string(Function.SwiftName);
11351169
/* TO_UPSTREAM(BoundsSafety) ON */
11361170
if (Function.ReturnBoundsSafety) {

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"
@@ -292,6 +293,29 @@ static void ProcessAPINotes(Sema &S, Decl *D,
292293
});
293294
}
294295

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

0 commit comments

Comments
 (0)