Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions clang/docs/APINotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,20 @@ declaration kind), all of which are optional:
- Name: vector
SwiftConformsTo: Cxx.CxxSequence

:SwiftSafety:

Import a declaration as ``@safe`` or ``@unsafe`` to Swift.

::

Tags:
- Name: UnsafeType
SwiftSafety: unsafe
- Name: span
Methods:
- Name: size
SwiftSafety: safe

:Availability, AvailabilityMsg:

A value of "nonswift" is equivalent to ``NS_SWIFT_UNAVAILABLE``. A value of
Expand Down
28 changes: 26 additions & 2 deletions clang/include/clang/APINotes/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ enum class SwiftNewTypeKind {
Enum,
};

enum class SwiftSafetyKind { Unspecified, Safe, Unsafe, None };

/// Describes API notes data for any entity.
///
/// This is used as the base of all API notes.
Expand All @@ -71,13 +73,19 @@ class CommonEntityInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftPrivate : 1;

LLVM_PREFERRED_TYPE(bool)
unsigned SwiftSafetyAudited : 1;

LLVM_PREFERRED_TYPE(SwiftSafetyKind)
unsigned SwiftSafety : 2;

public:
/// Swift name of this entity.
std::string SwiftName;

CommonEntityInfo()
: Unavailable(0), UnavailableInSwift(0), SwiftPrivateSpecified(0),
SwiftPrivate(0) {}
SwiftPrivate(0), SwiftSafetyAudited(0), SwiftSafety(0) {}

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

std::optional<SwiftSafetyKind> getSwiftSafety() const {
return SwiftSafetyAudited ? std::optional<SwiftSafetyKind>(
static_cast<SwiftSafetyKind>(SwiftSafety))
: std::nullopt;
}

void setSwiftSafety(SwiftSafetyKind Safety) {
SwiftSafetyAudited = 1;
SwiftSafety = static_cast<unsigned>(Safety);
}

friend bool operator==(const CommonEntityInfo &, const CommonEntityInfo &);

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

if (!SwiftSafetyAudited && RHS.SwiftSafetyAudited)
setSwiftSafety(*RHS.getSwiftSafety());

if (SwiftName.empty())
SwiftName = RHS.SwiftName;

Expand All @@ -123,7 +145,9 @@ inline bool operator==(const CommonEntityInfo &LHS,
LHS.Unavailable == RHS.Unavailable &&
LHS.UnavailableInSwift == RHS.UnavailableInSwift &&
LHS.SwiftPrivateSpecified == RHS.SwiftPrivateSpecified &&
LHS.SwiftPrivate == RHS.SwiftPrivate && LHS.SwiftName == RHS.SwiftName;
LHS.SwiftPrivate == RHS.SwiftPrivate &&
LHS.SwiftSafetyAudited == RHS.SwiftSafetyAudited &&
LHS.SwiftSafety == RHS.SwiftSafety && LHS.SwiftName == RHS.SwiftName;
}

inline bool operator!=(const CommonEntityInfo &LHS,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/APINotes/APINotesFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const uint16_t VERSION_MAJOR = 0;
/// API notes file minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
const uint16_t VERSION_MINOR = 37; // SwiftDestroyOp
const uint16_t VERSION_MINOR = 38; // SwiftSafety

const uint8_t kSwiftConforms = 1;
const uint8_t kSwiftDoesNotConform = 2;
Expand Down
13 changes: 8 additions & 5 deletions clang/lib/APINotes/APINotesReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,14 @@ class VersionedTableInfo {

/// Read serialized CommonEntityInfo.
void ReadCommonEntityInfo(const uint8_t *&Data, CommonEntityInfo &Info) {
uint8_t UnavailableBits = *Data++;
Info.Unavailable = (UnavailableBits >> 1) & 0x01;
Info.UnavailableInSwift = UnavailableBits & 0x01;
if ((UnavailableBits >> 2) & 0x01)
Info.setSwiftPrivate(static_cast<bool>((UnavailableBits >> 3) & 0x01));
uint8_t EncodedBits = *Data++;
Info.Unavailable = (EncodedBits >> 1) & 0x01;
Info.UnavailableInSwift = EncodedBits & 0x01;
if ((EncodedBits >> 2) & 0x01)
Info.setSwiftPrivate(static_cast<bool>((EncodedBits >> 3) & 0x01));
if ((EncodedBits >> 4) & 0x01)
Info.setSwiftSafety(
static_cast<SwiftSafetyKind>((EncodedBits >> 5) & 0x03));

unsigned MsgLength =
endian::readNext<uint16_t, llvm::endianness::little>(Data);
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/APINotes/APINotesTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ LLVM_DUMP_METHOD void CommonEntityInfo::dump(llvm::raw_ostream &OS) const {
OS << "[UnavailableInSwift] ";
if (SwiftPrivateSpecified)
OS << (SwiftPrivate ? "[SwiftPrivate] " : "");
if (SwiftSafetyAudited) {
switch (*getSwiftSafety()) {
case SwiftSafetyKind::Safe:
OS << "[Safe] ";
break;
case SwiftSafetyKind::Unsafe:
OS << "[Unsafe] ";
break;
case SwiftSafetyKind::Unspecified:
OS << "[Unspecified] ";
break;
case SwiftSafetyKind::None:
break;
}
}
if (!SwiftName.empty())
OS << "Swift Name: " << SwiftName << ' ';
OS << '\n';
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/APINotes/APINotesWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,12 @@ void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
llvm::support::endian::Writer writer(OS, llvm::endianness::little);

uint8_t payload = 0;
if (auto safety = CEI.getSwiftSafety()) {
payload = static_cast<unsigned>(*safety);
payload <<= 1;
payload |= 0x01;
}
payload <<= 2;
if (auto swiftPrivate = CEI.isSwiftPrivate()) {
payload |= 0x01;
if (*swiftPrivate)
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/APINotes/APINotesYAMLCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@
using namespace clang;
using namespace api_notes;

namespace llvm {
namespace yaml {
template <> struct ScalarEnumerationTraits<SwiftSafetyKind> {
static void enumeration(IO &IO, SwiftSafetyKind &SK) {
IO.enumCase(SK, "unspecified", SwiftSafetyKind::Unspecified);
IO.enumCase(SK, "safe", SwiftSafetyKind::Safe);
IO.enumCase(SK, "unsafe", SwiftSafetyKind::Unsafe);
}
};
} // namespace yaml
} // namespace llvm

namespace {
enum class APIAvailability {
Available = 0,
Expand Down Expand Up @@ -163,6 +175,7 @@ struct Method {
bool Required = false;
StringRef ResultType;
StringRef SwiftReturnOwnership;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
};

typedef std::vector<Method> MethodsSeq;
Expand Down Expand Up @@ -199,6 +212,7 @@ template <> struct MappingTraits<Method> {
IO.mapOptional("ResultType", M.ResultType, StringRef(""));
IO.mapOptional("SwiftReturnOwnership", M.SwiftReturnOwnership,
StringRef(""));
IO.mapOptional("SwiftSafety", M.SafetyKind, SwiftSafetyKind::None);
}
};
} // namespace yaml
Expand All @@ -214,6 +228,7 @@ struct Property {
StringRef SwiftName;
std::optional<bool> SwiftImportAsAccessors;
StringRef Type;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
};

typedef std::vector<Property> PropertiesSeq;
Expand All @@ -235,6 +250,7 @@ template <> struct MappingTraits<Property> {
IO.mapOptional("SwiftName", P.SwiftName, StringRef(""));
IO.mapOptional("SwiftImportAsAccessors", P.SwiftImportAsAccessors);
IO.mapOptional("Type", P.Type, StringRef(""));
IO.mapOptional("SwiftSafety", P.SafetyKind, SwiftSafetyKind::None);
}
};
} // namespace yaml
Expand All @@ -254,6 +270,7 @@ struct Class {
std::optional<std::string> SwiftConformance;
MethodsSeq Methods;
PropertiesSeq Properties;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
};

typedef std::vector<Class> ClassesSeq;
Expand All @@ -279,6 +296,7 @@ template <> struct MappingTraits<Class> {
IO.mapOptional("SwiftConformsTo", C.SwiftConformance);
IO.mapOptional("Methods", C.Methods);
IO.mapOptional("Properties", C.Properties);
IO.mapOptional("SwiftSafety", C.SafetyKind, SwiftSafetyKind::None);
}
};
} // namespace yaml
Expand All @@ -297,6 +315,7 @@ struct Function {
StringRef Type;
StringRef ResultType;
StringRef SwiftReturnOwnership;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
};

typedef std::vector<Function> FunctionsSeq;
Expand All @@ -321,6 +340,7 @@ template <> struct MappingTraits<Function> {
IO.mapOptional("ResultType", F.ResultType, StringRef(""));
IO.mapOptional("SwiftReturnOwnership", F.SwiftReturnOwnership,
StringRef(""));
IO.mapOptional("SwiftSafety", F.SafetyKind, SwiftSafetyKind::None);
}
};
} // namespace yaml
Expand All @@ -334,6 +354,7 @@ struct GlobalVariable {
std::optional<bool> SwiftPrivate;
StringRef SwiftName;
StringRef Type;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
};

typedef std::vector<GlobalVariable> GlobalVariablesSeq;
Expand All @@ -353,6 +374,7 @@ template <> struct MappingTraits<GlobalVariable> {
IO.mapOptional("SwiftPrivate", GV.SwiftPrivate);
IO.mapOptional("SwiftName", GV.SwiftName, StringRef(""));
IO.mapOptional("Type", GV.Type, StringRef(""));
IO.mapOptional("SwiftSafety", GV.SafetyKind, SwiftSafetyKind::None);
}
};
} // namespace yaml
Expand All @@ -364,6 +386,7 @@ struct EnumConstant {
AvailabilityItem Availability;
std::optional<bool> SwiftPrivate;
StringRef SwiftName;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
};

typedef std::vector<EnumConstant> EnumConstantsSeq;
Expand All @@ -381,6 +404,7 @@ template <> struct MappingTraits<EnumConstant> {
IO.mapOptional("AvailabilityMsg", EC.Availability.Msg, StringRef(""));
IO.mapOptional("SwiftPrivate", EC.SwiftPrivate);
IO.mapOptional("SwiftName", EC.SwiftName, StringRef(""));
IO.mapOptional("SwiftSafety", EC.SafetyKind, SwiftSafetyKind::None);
}
};
} // namespace yaml
Expand Down Expand Up @@ -424,6 +448,7 @@ struct Field {
std::optional<bool> SwiftPrivate;
StringRef SwiftName;
StringRef Type;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
};

typedef std::vector<Field> FieldsSeq;
Expand All @@ -443,6 +468,7 @@ template <> struct MappingTraits<Field> {
IO.mapOptional("SwiftPrivate", F.SwiftPrivate);
IO.mapOptional("SwiftName", F.SwiftName, StringRef(""));
IO.mapOptional("Type", F.Type, StringRef(""));
IO.mapOptional("SwiftSafety", F.SafetyKind, SwiftSafetyKind::None);
}
};
} // namespace yaml
Expand Down Expand Up @@ -470,6 +496,7 @@ struct Tag {
std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
std::optional<bool> SwiftCopyable;
std::optional<bool> SwiftEscapable;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
FunctionsSeq Methods;
FieldsSeq Fields;

Expand Down Expand Up @@ -515,6 +542,7 @@ template <> struct MappingTraits<Tag> {
IO.mapOptional("Methods", T.Methods);
IO.mapOptional("Fields", T.Fields);
IO.mapOptional("Tags", T.Tags);
IO.mapOptional("SwiftSafety", T.SafetyKind, SwiftSafetyKind::None);
}
};
} // namespace yaml
Expand All @@ -530,6 +558,7 @@ struct Typedef {
std::optional<StringRef> NSErrorDomain;
std::optional<SwiftNewTypeKind> SwiftType;
std::optional<std::string> SwiftConformance;
const SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
};

typedef std::vector<Typedef> TypedefsSeq;
Expand Down Expand Up @@ -602,6 +631,7 @@ struct Namespace {
StringRef SwiftName;
std::optional<bool> SwiftPrivate;
TopLevelItems Items;
const SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
};
} // namespace

Expand Down Expand Up @@ -797,6 +827,8 @@ class YAMLConverter {
StringRef APIName) {
convertAvailability(Common.Availability, Info, APIName);
Info.setSwiftPrivate(Common.SwiftPrivate);
if (Common.SafetyKind != SwiftSafetyKind::None)
Info.setSwiftSafety(Common.SafetyKind);
Info.SwiftName = std::string(Common.SwiftName);
}

Expand Down Expand Up @@ -956,6 +988,8 @@ class YAMLConverter {
void convertFunction(const Function &Function, FuncOrMethodInfo &FI) {
convertAvailability(Function.Availability, FI, Function.Name);
FI.setSwiftPrivate(Function.SwiftPrivate);
if (Function.SafetyKind != SwiftSafetyKind::None)
FI.setSwiftSafety(Function.SafetyKind);
FI.SwiftName = std::string(Function.SwiftName);
std::optional<ParamInfo> This;
convertParams(Function.Params, FI, This);
Expand Down
24 changes: 24 additions & 0 deletions clang/lib/Sema/SemaAPINotes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "CheckExprLifetime.h"
#include "TypeLocBuilder.h"
#include "clang/APINotes/APINotesReader.h"
#include "clang/APINotes/Types.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
Expand Down Expand Up @@ -291,6 +292,29 @@ static void ProcessAPINotes(Sema &S, Decl *D,
});
}

// swift_safety
if (auto SafetyKind = Info.getSwiftSafety()) {
bool Addition = *SafetyKind != api_notes::SwiftSafetyKind::Unspecified;
handleAPINotedAttribute<SwiftAttrAttr>(
S, D, Addition, Metadata,
[&] {
return SwiftAttrAttr::Create(
S.Context, *SafetyKind == api_notes::SwiftSafetyKind::Safe
? "safe"
: "unsafe");
},
[](const Decl *D) {
return llvm::find_if(D->attrs(), [](const Attr *attr) {
if (const auto *swiftAttr = dyn_cast<SwiftAttrAttr>(attr)) {
if (swiftAttr->getAttribute() == "safe" ||
swiftAttr->getAttribute() == "unsafe")
return true;
}
return false;
});
});
}

// swift_name
if (!Info.SwiftName.empty()) {
handleAPINotedAttribute<SwiftNameAttr>(
Expand Down
Loading
Loading