Merge pull request #75413 from DougGregor/unsafe

Introduce `@unsafe` and the ability to prohibit use of unsafe entities
This commit is contained in:
Doug Gregor
2024-08-20 06:14:39 -07:00
committed by GitHub
49 changed files with 596 additions and 41 deletions

View File

@@ -357,7 +357,7 @@ protected:
// for the inline bitfields.
union { uint64_t OpaqueBits;
SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1+1+1+1+1+1+1+1,
SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1+1+1+1+1+1+1+1+1,
Kind : bitmax(NumDeclKindBits,8),
/// Whether this declaration is invalid.
@@ -372,10 +372,6 @@ protected:
/// Use getClangNode() to retrieve the corresponding Clang AST.
FromClang : 1,
/// Whether this declaration was added to the surrounding
/// DeclContext of an active #if config clause.
EscapedFromIfConfig : 1,
/// Whether this declaration is syntactically scoped inside of
/// a local context, but should behave like a top-level
/// declaration for name lookup purposes. This is used by
@@ -404,7 +400,13 @@ protected:
/// True if we're in the common case where the SPIGroupsRequest
/// request returned an empty array of identifiers.
NoSPIGroups : 1
NoSPIGroups : 1,
/// True if we have computed whether this declaration is unsafe.
IsUnsafeComputed : 1,
/// True if this declaration has been determined to be "unsafe".
IsUnsafe : 1
);
SWIFT_INLINE_BITFIELD_FULL(PatternBindingDecl, Decl, 1+1+2+16,
@@ -857,6 +859,7 @@ protected:
friend class ExpandPeerMacroRequest;
friend class GlobalActorAttributeRequest;
friend class SPIGroupsRequest;
friend class IsUnsafeRequest;
private:
llvm::PointerUnion<DeclContext *, ASTContext *> Context;
@@ -916,12 +919,13 @@ protected:
Bits.Decl.Invalid = false;
Bits.Decl.Implicit = false;
Bits.Decl.FromClang = false;
Bits.Decl.EscapedFromIfConfig = false;
Bits.Decl.Hoisted = false;
Bits.Decl.LacksObjCInterfaceOrImplementation = false;
Bits.Decl.NoMemberAttributeMacros = false;
Bits.Decl.NoGlobalActorAttribute = false;
Bits.Decl.NoSPIGroups = false;
Bits.Decl.IsUnsafeComputed = false;
Bits.Decl.IsUnsafe = false;
}
/// Get the Clang node associated with this declaration.
@@ -1180,15 +1184,26 @@ public:
/// Whether this declaration predates the introduction of concurrency.
bool preconcurrency() const;
/// Whether this declaration is considered "unsafe", i.e., should not be
/// used in a "safe" dialect.
bool isUnsafe() const;
private:
bool isUnsafeComputed() const {
return Bits.Decl.IsUnsafeComputed;
}
bool isUnsafeRaw() const {
return Bits.Decl.IsUnsafe;
}
void setUnsafe(bool value) {
assert(!Bits.Decl.IsUnsafeComputed);
Bits.Decl.IsUnsafe = value;
Bits.Decl.IsUnsafeComputed = true;
}
public:
bool escapedFromIfConfig() const {
return Bits.Decl.EscapedFromIfConfig;
}
void setEscapedFromIfConfig(bool Escaped) {
Bits.Decl.EscapedFromIfConfig = Escaped;
}
bool getSemanticAttrsComputed() const {
return Bits.Decl.SemanticAttrsComputed;
}

View File

@@ -500,7 +500,13 @@ SIMPLE_DECL_ATTR(sensitive, Sensitive,
OnStruct | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
159)
LAST_DECL_ATTR(PreInverseGenerics)
SIMPLE_DECL_ATTR(unsafe, Unsafe,
OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType |
UserInaccessible |
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
160)
LAST_DECL_ATTR(Unsafe)
#undef DECL_ATTR_ALIAS
#undef CONTEXTUAL_DECL_ATTR_ALIAS

View File

@@ -7964,5 +7964,33 @@ NOTE(sending_function_result_with_sending_param_note, none,
"isolation domain through a result of an invocation of value",
())
//------------------------------------------------------------------------------
// MARK: Strict Safety Diagnostics
//------------------------------------------------------------------------------
ERROR(unsafe_attr_disabled,none,
"attribute requires '-enable-experimental-feature AllowUnsafeAttribute'", ())
WARNING(override_safe_withunsafe,none,
"override of safe %0 with unsafe %0", (DescriptiveDeclKind))
WARNING(witness_unsafe,none,
"unsafe %0 %1 cannot satisfy safe requirement",
(DescriptiveDeclKind, DeclName))
WARNING(type_witness_unsafe,none,
"unsafe type %0 cannot satisfy safe associated type %1",
(Type, DeclName))
WARNING(unchecked_conformance_is_unsafe,none,
"@unchecked conformance involves unsafe code", ())
WARNING(unowned_unsafe_is_unsafe,none,
"unowned(unsafe) involves unsafe code", ())
WARNING(nonisolated_unsafe_is_unsafe,none,
"nonisolated(unsafe) involves unsafe code", ())
WARNING(reference_to_unsafe_decl,none,
"%select{reference|call}0 to unsafe %kindbase1",
(bool, const ValueDecl *))
WARNING(reference_to_unsafe_typed_decl,none,
"%select{reference|call}0 to %kindbase1 involves unsafe type %2",
(bool, const ValueDecl *, Type))
NOTE(unsafe_decl_here,none,
"unsafe %kindbase0 declared here", (const ValueDecl *))
#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"

View File

@@ -5065,6 +5065,24 @@ public:
bool isCached() const { return true; }
};
class IsUnsafeRequest
: public SimpleRequest<IsUnsafeRequest,
bool(Decl *decl),
RequestFlags::SeparatelyCached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
bool evaluate(Evaluator &evaluator, Decl *decl) const;
public:
bool isCached() const { return true; }
std::optional<bool> getCachedResult() const;
void cacheResult(bool value) const;
};
#define SWIFT_TYPEID_ZONE TypeChecker
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
#include "swift/Basic/DefineTypeIDZone.h"

View File

@@ -593,3 +593,6 @@ SWIFT_REQUEST(TypeChecker, CaptureInfoRequest,
SWIFT_REQUEST(TypeChecker, ParamCaptureInfoRequest,
CaptureInfo(ParamDecl *),
SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsUnsafeRequest,
bool(Decl *),
SeparatelyCached, NoLocationInfo)

View File

@@ -185,7 +185,10 @@ public:
/// Contains a PackArchetypeType. Also implies HasPrimaryArchetype.
HasPackArchetype = 0x20000,
Last_Property = HasPackArchetype
/// Whether this type contains an unsafe type.
IsUnsafe = 0x040000,
Last_Property = IsUnsafe
};
enum { BitWidth = countBitsUsed(Property::Last_Property) };
@@ -266,6 +269,8 @@ public:
bool hasPackArchetype() const { return Bits & HasPackArchetype; }
bool isUnsafe() const { return Bits & IsUnsafe; }
/// Does a type with these properties structurally contain a
/// parameterized existential type?
bool hasParameterizedExistential() const {
@@ -431,12 +436,12 @@ protected:
NumProtocols : 16
);
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 7+29,
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 7+28,
/// Type variable options.
Options : 7,
: NumPadBits,
/// The unique number assigned to this type variable.
ID : 29
ID : 28
);
SWIFT_INLINE_BITFIELD_FULL(ErrorUnionType, TypeBase, 32,
@@ -709,6 +714,11 @@ public:
return getRecursiveProperties().hasPackArchetype();
}
/// Whether the type contains an @unsafe type in it anywhere.
bool isUnsafe() const {
return getRecursiveProperties().isUnsafe();
}
/// Determine whether the type involves a primary, pack or local archetype.
///
/// FIXME: Replace all remaining callers with a more precise check.
@@ -6637,7 +6647,8 @@ private:
GenericEnvironment *GenericEnv,
Type InterfaceType,
ArrayRef<ProtocolDecl *> ConformsTo,
Type Superclass, LayoutConstraint Layout);
Type Superclass, LayoutConstraint Layout,
RecursiveTypeProperties Properties);
};
BEGIN_CAN_TYPE_WRAPPER(PrimaryArchetypeType, ArchetypeType)
END_CAN_TYPE_WRAPPER(PrimaryArchetypeType, ArchetypeType)
@@ -6918,7 +6929,8 @@ public:
private:
PackArchetypeType(const ASTContext &Ctx, GenericEnvironment *GenericEnv,
Type InterfaceType, ArrayRef<ProtocolDecl *> ConformsTo,
Type Superclass, LayoutConstraint Layout, PackShape Shape);
Type Superclass, LayoutConstraint Layout, PackShape Shape,
RecursiveTypeProperties properties);
};
BEGIN_CAN_TYPE_WRAPPER(PackArchetypeType, ArchetypeType)
END_CAN_TYPE_WRAPPER(PackArchetypeType, ArchetypeType)