Skip to content

Commit ee7a1cd

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

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 = 38; // 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
@@ -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
@@ -514,6 +514,12 @@ void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
514514
llvm::support::endian::Writer writer(OS, llvm::endianness::little);
515515

516516
uint8_t payload = 0;
517+
if (auto safety = CEI.getSwiftSafety()) {
518+
payload = static_cast<unsigned>(*safety);
519+
payload <<= 1;
520+
payload |= 0x01;
521+
}
522+
payload <<= 2;
517523
if (auto swiftPrivate = CEI.isSwiftPrivate()) {
518524
payload |= 0x01;
519525
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
@@ -638,6 +664,7 @@ struct Tag {
638664
std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
639665
std::optional<bool> SwiftCopyable;
640666
std::optional<bool> SwiftEscapable;
667+
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
641668
FunctionsSeq Methods;
642669
FieldsSeq Fields;
643670

@@ -683,6 +710,7 @@ template <> struct MappingTraits<Tag> {
683710
IO.mapOptional("Methods", T.Methods);
684711
IO.mapOptional("Fields", T.Fields);
685712
IO.mapOptional("Tags", T.Tags);
713+
IO.mapOptional("SwiftSafety", T.SafetyKind, SwiftSafetyKind::None);
686714
}
687715
};
688716
} // namespace yaml
@@ -698,6 +726,7 @@ struct Typedef {
698726
std::optional<StringRef> NSErrorDomain;
699727
std::optional<SwiftNewTypeKind> SwiftType;
700728
std::optional<std::string> SwiftConformance;
729+
const SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
701730
};
702731

703732
typedef std::vector<Typedef> TypedefsSeq;
@@ -770,6 +799,7 @@ struct Namespace {
770799
StringRef SwiftName;
771800
std::optional<bool> SwiftPrivate;
772801
TopLevelItems Items;
802+
const SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
773803
};
774804
} // namespace
775805

@@ -974,6 +1004,8 @@ class YAMLConverter {
9741004
StringRef APIName) {
9751005
convertAvailability(Common.Availability, Info, APIName);
9761006
Info.setSwiftPrivate(Common.SwiftPrivate);
1007+
if (Common.SafetyKind != SwiftSafetyKind::None)
1008+
Info.setSwiftSafety(Common.SafetyKind);
9771009
Info.SwiftName = std::string(Common.SwiftName);
9781010
}
9791011

@@ -1133,6 +1165,8 @@ class YAMLConverter {
11331165
void convertFunction(const Function &Function, FuncOrMethodInfo &FI) {
11341166
convertAvailability(Function.Availability, FI, Function.Name);
11351167
FI.setSwiftPrivate(Function.SwiftPrivate);
1168+
if (Function.SafetyKind != SwiftSafetyKind::None)
1169+
FI.setSwiftSafety(Function.SafetyKind);
11361170
FI.SwiftName = std::string(Function.SwiftName);
11371171
/* TO_UPSTREAM(BoundsSafety) ON */
11381172
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"
@@ -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)