Skip to content

Commit 9af4d6e

Browse files
authored
Merge pull request swiftlang#78730 from DougGregor/safe-attr
Introduce the @safe attribute as described in the opt-in safety checking proposal
2 parents 0901587 + 7202402 commit 9af4d6e

32 files changed

+257
-157
lines changed

include/swift/AST/Decl.h

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,16 @@ enum class AssociatedValueCheck {
235235
HasAssociatedValues,
236236
};
237237

238+
/// An explicit declaration of the safety of
239+
enum class ExplicitSafety {
240+
/// There was no explicit declaration of the safety of the given entity.
241+
Unspecified,
242+
/// The entity was explicitly declared safe with @safe.
243+
Safe,
244+
/// The entity was explicitly declared unsafe with @unsafe.
245+
Unsafe
246+
};
247+
238248
/// Diagnostic printing of \c StaticSpellingKind.
239249
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, StaticSpellingKind SSK);
240250

@@ -859,7 +869,6 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
859869
friend class ExpandPeerMacroRequest;
860870
friend class GlobalActorAttributeRequest;
861871
friend class SPIGroupsRequest;
862-
friend class IsUnsafeRequest;
863872

864873
private:
865874
llvm::PointerUnion<DeclContext *, ASTContext *> Context;
@@ -1203,9 +1212,9 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
12031212
/// Whether this declaration predates the introduction of concurrency.
12041213
bool preconcurrency() const;
12051214

1206-
/// Whether this declaration is considered "unsafe", i.e., should not be
1207-
/// used in a "safe" dialect.
1208-
bool isUnsafe() const;
1215+
/// Query whether this declaration was explicitly declared to be safe or
1216+
/// unsafe.
1217+
ExplicitSafety getExplicitSafety() const;
12091218

12101219
private:
12111220
bool isUnsafeComputed() const {
@@ -1816,8 +1825,13 @@ struct InheritedEntry : public TypeLoc {
18161825
bool isPreconcurrency() const {
18171826
return getOptions().contains(ProtocolConformanceFlags::Preconcurrency);
18181827
}
1819-
bool isUnsafe() const {
1820-
return getOptions().contains(ProtocolConformanceFlags::Unsafe);
1828+
1829+
ExplicitSafety getExplicitSafety() const {
1830+
if (getOptions().contains(ProtocolConformanceFlags::Unsafe))
1831+
return ExplicitSafety::Unsafe;
1832+
if (getOptions().contains(ProtocolConformanceFlags::Safe))
1833+
return ExplicitSafety::Safe;
1834+
return ExplicitSafety::Unspecified;
18211835
}
18221836

18231837
bool isSuppressed() const { return IsSuppressed; }
@@ -1826,6 +1840,21 @@ struct InheritedEntry : public TypeLoc {
18261840
RawOptions = (getOptions() | flag).toRaw();
18271841
}
18281842

1843+
void setOption(ExplicitSafety safety) {
1844+
RawOptions = (getOptions() - ProtocolConformanceFlags::Unsafe
1845+
- ProtocolConformanceFlags::Safe).toRaw();
1846+
switch (safety) {
1847+
case ExplicitSafety::Unspecified:
1848+
break;
1849+
case ExplicitSafety::Safe:
1850+
RawOptions = (getOptions() | ProtocolConformanceFlags::Safe).toRaw();
1851+
break;
1852+
case ExplicitSafety::Unsafe:
1853+
RawOptions = (getOptions() | ProtocolConformanceFlags::Unsafe).toRaw();
1854+
break;
1855+
}
1856+
}
1857+
18291858
void setSuppressed() {
18301859
assert(!IsSuppressed && "setting suppressed again!?");
18311860
IsSuppressed = true;

include/swift/AST/DeclAttr.def

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ SIMPLE_DECL_ATTR(sensitive, Sensitive,
516516
SIMPLE_DECL_ATTR(unsafe, Unsafe,
517517
OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType |
518518
OnExtension | OnTypeAlias | OnEnumElement | UserInaccessible |
519-
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
519+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
520520
160)
521521

522522
DECL_ATTR(lifetime, Lifetime,
@@ -531,7 +531,11 @@ SIMPLE_DECL_ATTR(_addressableForDependencies, AddressableForDependencies,
531531
OnNominalType | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UserInaccessible,
532532
163)
533533

534-
// 164 was the never-shipped @safe attribute and can be reused
534+
SIMPLE_DECL_ATTR(safe, Safe,
535+
OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType |
536+
OnExtension | OnEnumElement | UserInaccessible |
537+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
538+
164)
535539

536540
DECL_ATTR(abi, ABI,
537541
OnAbstractFunction | OnVar /* will eventually add types */ | LongAttribute | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8126,9 +8126,13 @@ NOTE(note_use_of_unsafe_conformance_is_unsafe,none,
81268126
(Type, const ValueDecl *))
81278127

81288128
GROUPED_WARNING(decl_signature_involves_unsafe,Unsafe,none,
8129-
"%kindbase0 has an interface that is not memory-safe; "
8130-
"use '@unsafe' to indicate that its use is unsafe",
8129+
"%kindbase0 has an interface that involves unsafe types",
81318130
(const Decl *))
8131+
NOTE(decl_signature_mark_unsafe,none,
8132+
"add '@unsafe' to indicate that this declaration is unsafe to use",
8133+
())
8134+
NOTE(decl_signature_mark_safe,none,
8135+
"add '@safe' to indicate that this declaration is memory-safe to use", ())
81328136

81338137
GROUPED_WARNING(conformance_involves_unsafe,Unsafe,none,
81348138
"conformance of %0 to %kind1 involves unsafe code; use '@unsafe' to "

include/swift/AST/ProtocolConformance.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -654,9 +654,14 @@ class NormalProtocolConformance : public RootProtocolConformance,
654654
/// known.
655655
SourceLoc getPreconcurrencyLoc() const { return PreconcurrencyLoc; }
656656

657-
/// Whether this is an "unsafe" conformance.
658-
bool isUnsafe() const {
659-
return getOptions().contains(ProtocolConformanceFlags::Unsafe);
657+
/// Query whether this conformance was explicitly declared to be safe or
658+
/// unsafe.
659+
ExplicitSafety getExplicitSafety() const {
660+
if (getOptions().contains(ProtocolConformanceFlags::Unsafe))
661+
return ExplicitSafety::Unsafe;
662+
if (getOptions().contains(ProtocolConformanceFlags::Safe))
663+
return ExplicitSafety::Safe;
664+
return ExplicitSafety::Unspecified;
660665
}
661666

662667
/// Determine whether we've lazily computed the associated conformance array

include/swift/AST/ProtocolConformanceOptions.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ enum class ProtocolConformanceFlags {
3434
/// @retroactive conformance
3535
Retroactive = 0x08,
3636

37+
/// @safe conformance
38+
Safe = 0x10,
39+
3740
// Note: whenever you add a bit here, update
3841
// NumProtocolConformanceOptions below.
3942
};
@@ -49,7 +52,7 @@ inline ProtocolConformanceOptions operator|(
4952
}
5053

5154
enum : unsigned {
52-
NumProtocolConformanceOptions = 4
55+
NumProtocolConformanceOptions = 5
5356
};
5457

5558
} // end namespace swift

include/swift/AST/TypeCheckRequests.h

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5175,24 +5175,6 @@ void simple_display(llvm::raw_ostream &out,
51755175
RegexLiteralPatternFeatureKind kind);
51765176
SourceLoc extractNearestSourceLoc(RegexLiteralPatternFeatureKind kind);
51775177

5178-
class IsUnsafeRequest
5179-
: public SimpleRequest<IsUnsafeRequest,
5180-
bool(Decl *decl),
5181-
RequestFlags::SeparatelyCached> {
5182-
public:
5183-
using SimpleRequest::SimpleRequest;
5184-
5185-
private:
5186-
friend SimpleRequest;
5187-
5188-
bool evaluate(Evaluator &evaluator, Decl *decl) const;
5189-
5190-
public:
5191-
bool isCached() const { return true; }
5192-
std::optional<bool> getCachedResult() const;
5193-
void cacheResult(bool value) const;
5194-
};
5195-
51965178
class GenericTypeParamDeclGetValueTypeRequest
51975179
: public SimpleRequest<GenericTypeParamDeclGetValueTypeRequest,
51985180
Type(GenericTypeParamDecl *decl),

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -605,9 +605,6 @@ SWIFT_REQUEST(TypeChecker, CaptureInfoRequest,
605605
SWIFT_REQUEST(TypeChecker, ParamCaptureInfoRequest,
606606
CaptureInfo(ParamDecl *),
607607
SeparatelyCached, NoLocationInfo)
608-
SWIFT_REQUEST(TypeChecker, IsUnsafeRequest,
609-
bool(Decl *),
610-
SeparatelyCached, NoLocationInfo)
611608
SWIFT_REQUEST(TypeChecker, CustomDerivativesRequest,
612609
CustomDerivativesResult(SourceFile *),
613610
Cached, NoLocationInfo)

include/swift/Sema/ConstraintSystem.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
#include "swift/AST/ASTVisitor.h"
2424
#include "swift/AST/ASTWalker.h"
2525
#include "swift/AST/AnyFunctionRef.h"
26-
#include "swift/AST/DiagnosticsSema.h"
2726
#include "swift/AST/NameLookup.h"
2827
#include "swift/AST/PropertyWrappers.h"
2928
#include "swift/AST/Types.h"

lib/AST/ASTContext.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4076,7 +4076,8 @@ get(GenericTypeDecl *TheDecl, Type Parent, const ASTContext &C) {
40764076
UnboundGenericType::Profile(ID, TheDecl, Parent);
40774077
void *InsertPos = nullptr;
40784078
RecursiveTypeProperties properties;
4079-
if (TheDecl->isUnsafe()) properties |= RecursiveTypeProperties::IsUnsafe;
4079+
if (TheDecl->getExplicitSafety() == ExplicitSafety::Unsafe)
4080+
properties |= RecursiveTypeProperties::IsUnsafe;
40804081
if (Parent) properties |= Parent->getRecursiveProperties();
40814082

40824083
auto arena = getArena(properties);
@@ -4129,7 +4130,8 @@ BoundGenericType *BoundGenericType::get(NominalTypeDecl *TheDecl,
41294130
llvm::FoldingSetNodeID ID;
41304131
BoundGenericType::Profile(ID, TheDecl, Parent, GenericArgs);
41314132
RecursiveTypeProperties properties;
4132-
if (TheDecl->isUnsafe()) properties |= RecursiveTypeProperties::IsUnsafe;
4133+
if (TheDecl->getExplicitSafety() == ExplicitSafety::Unsafe)
4134+
properties |= RecursiveTypeProperties::IsUnsafe;
41334135
if (Parent) properties |= Parent->getRecursiveProperties();
41344136
for (Type Arg : GenericArgs) {
41354137
properties |= Arg->getRecursiveProperties();
@@ -4211,7 +4213,8 @@ EnumType::EnumType(EnumDecl *TheDecl, Type Parent, const ASTContext &C,
42114213

42124214
EnumType *EnumType::get(EnumDecl *D, Type Parent, const ASTContext &C) {
42134215
RecursiveTypeProperties properties;
4214-
if (D->isUnsafe()) properties |= RecursiveTypeProperties::IsUnsafe;
4216+
if (D->getExplicitSafety() == ExplicitSafety::Unsafe)
4217+
properties |= RecursiveTypeProperties::IsUnsafe;
42154218
if (Parent) properties |= Parent->getRecursiveProperties();
42164219
auto arena = getArena(properties);
42174220

@@ -4228,7 +4231,8 @@ StructType::StructType(StructDecl *TheDecl, Type Parent, const ASTContext &C,
42284231

42294232
StructType *StructType::get(StructDecl *D, Type Parent, const ASTContext &C) {
42304233
RecursiveTypeProperties properties;
4231-
if (D->isUnsafe()) properties |= RecursiveTypeProperties::IsUnsafe;
4234+
if (D->getExplicitSafety() == ExplicitSafety::Unsafe)
4235+
properties |= RecursiveTypeProperties::IsUnsafe;
42324236
if (Parent) properties |= Parent->getRecursiveProperties();
42334237
auto arena = getArena(properties);
42344238

@@ -4245,7 +4249,8 @@ ClassType::ClassType(ClassDecl *TheDecl, Type Parent, const ASTContext &C,
42454249

42464250
ClassType *ClassType::get(ClassDecl *D, Type Parent, const ASTContext &C) {
42474251
RecursiveTypeProperties properties;
4248-
if (D->isUnsafe()) properties |= RecursiveTypeProperties::IsUnsafe;
4252+
if (D->getExplicitSafety() == ExplicitSafety::Unsafe)
4253+
properties |= RecursiveTypeProperties::IsUnsafe;
42494254
if (Parent) properties |= Parent->getRecursiveProperties();
42504255
auto arena = getArena(properties);
42514256

@@ -5396,7 +5401,8 @@ OptionalType *OptionalType::get(Type base) {
53965401
ProtocolType *ProtocolType::get(ProtocolDecl *D, Type Parent,
53975402
const ASTContext &C) {
53985403
RecursiveTypeProperties properties;
5399-
if (D->isUnsafe()) properties |= RecursiveTypeProperties::IsUnsafe;
5404+
if (D->getExplicitSafety() == ExplicitSafety::Unsafe)
5405+
properties |= RecursiveTypeProperties::IsUnsafe;
54005406
if (Parent) properties |= Parent->getRecursiveProperties();
54015407
auto arena = getArena(properties);
54025408

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4770,6 +4770,7 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
47704770
requires_stored_property_inits)
47714771
TRIVIAL_ATTR_PRINTER(ResultBuilder, result_builder)
47724772
TRIVIAL_ATTR_PRINTER(Rethrows, rethrows)
4773+
TRIVIAL_ATTR_PRINTER(Safe, safe)
47734774
TRIVIAL_ATTR_PRINTER(SPIOnly, spi_only)
47744775
TRIVIAL_ATTR_PRINTER(Sendable, sendable)
47754776
TRIVIAL_ATTR_PRINTER(Sensitive, sensitive)

0 commit comments

Comments
 (0)