Skip to content

Commit 6855dc4

Browse files
committed
Uses of @exclusivity(unsafe) variables are unsafe
1 parent 33bff48 commit 6855dc4

File tree

5 files changed

+61
-0
lines changed

5 files changed

+61
-0
lines changed

include/swift/AST/DiagnosticsSema.def

+5
Original file line numberDiff line numberDiff line change
@@ -8097,6 +8097,8 @@ NOTE(note_reference_to_nonisolated_unsafe,none,
80978097
(const ValueDecl *))
80988098
NOTE(note_reference_unowned_unsafe,none,
80998099
"reference to unowned(unsafe) %kind0 is unsafe", (const ValueDecl *))
8100+
NOTE(note_reference_exclusivity_unchecked,none,
8101+
"reference to @exclusivity(unchecked) %kind0 is unsafe", (const ValueDecl *))
81008102
NOTE(note_use_of_unsafe_conformance_is_unsafe,none,
81018103
"@unsafe conformance of %0 to %kind1 involves unsafe code",
81028104
(Type, const ValueDecl *))
@@ -8118,6 +8120,9 @@ GROUPED_WARNING(use_of_unsafe_conformance_is_unsafe,Unsafe,none,
81188120
(Type, const ValueDecl *))
81198121
GROUPED_WARNING(reference_unowned_unsafe,Unsafe,none,
81208122
"reference to unowned(unsafe) %kind0 is unsafe", (const ValueDecl *))
8123+
GROUPED_WARNING(reference_exclusivity_unchecked,Unsafe,none,
8124+
"reference to @exclusivity(unchecked) %kind0 is unsafe", (const ValueDecl *))
8125+
81218126
GROUPED_WARNING(reference_to_nonisolated_unsafe,Unsafe,none,
81228127
"reference to nonisolated(unsafe) %kind0 is unsafe in concurrently-executing code",
81238128
(const ValueDecl *))

include/swift/AST/UnsafeUse.h

+15
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class UnsafeUse {
3939
UnsafeConformance,
4040
/// A reference to an unowned(unsafe) entity.
4141
UnownedUnsafe,
42+
/// A reference to an @exclusivity(unchecked) entity.
43+
ExclusivityUnchecked,
4244
/// A reference to a nonisolated(unsafe) entity.
4345
NonisolatedUnsafe,
4446
/// A reference to an unsafe declaration.
@@ -111,6 +113,7 @@ class UnsafeUse {
111113
SourceLoc location
112114
) {
113115
assert(kind == UnownedUnsafe ||
116+
kind == ExclusivityUnchecked ||
114117
kind == NonisolatedUnsafe ||
115118
kind == ReferenceToUnsafe ||
116119
kind == ReferenceToUnsafeThroughTypealias ||
@@ -166,6 +169,12 @@ class UnsafeUse {
166169
return forReference(UnownedUnsafe, dc, decl, Type(), location);
167170
}
168171

172+
static UnsafeUse forExclusivityUnchecked(const Decl *decl,
173+
SourceLoc location,
174+
DeclContext *dc) {
175+
return forReference(ExclusivityUnchecked, dc, decl, Type(), location);
176+
}
177+
169178
static UnsafeUse forNonisolatedUnsafe(const Decl *decl,
170179
SourceLoc location,
171180
DeclContext *dc) {
@@ -215,6 +224,7 @@ class UnsafeUse {
215224
(const char *)storage.typeWitness.location));
216225

217226
case UnownedUnsafe:
227+
case ExclusivityUnchecked:
218228
case NonisolatedUnsafe:
219229
case ReferenceToUnsafe:
220230
case ReferenceToUnsafeThroughTypealias:
@@ -238,6 +248,7 @@ class UnsafeUse {
238248
return storage.typeWitness.assocType;
239249

240250
case UnownedUnsafe:
251+
case ExclusivityUnchecked:
241252
case NonisolatedUnsafe:
242253
case ReferenceToUnsafe:
243254
case ReferenceToUnsafeThroughTypealias:
@@ -262,6 +273,7 @@ class UnsafeUse {
262273
DeclContext *getDeclContext() const {
263274
switch (getKind()) {
264275
case UnownedUnsafe:
276+
case ExclusivityUnchecked:
265277
case NonisolatedUnsafe:
266278
case ReferenceToUnsafe:
267279
case ReferenceToUnsafeThroughTypealias:
@@ -294,6 +306,7 @@ class UnsafeUse {
294306

295307
case TypeWitness:
296308
case UnownedUnsafe:
309+
case ExclusivityUnchecked:
297310
case NonisolatedUnsafe:
298311
case ReferenceToUnsafe:
299312
case ReferenceToUnsafeThroughTypealias:
@@ -319,6 +332,7 @@ class UnsafeUse {
319332
return storage.typeWitness.type;
320333

321334
case UnownedUnsafe:
335+
case ExclusivityUnchecked:
322336
case NonisolatedUnsafe:
323337
case ReferenceToUnsafe:
324338
case ReferenceToUnsafeThroughTypealias:
@@ -342,6 +356,7 @@ class UnsafeUse {
342356

343357
case Override:
344358
case UnownedUnsafe:
359+
case ExclusivityUnchecked:
345360
case NonisolatedUnsafe:
346361
case ReferenceToUnsafe:
347362
case ReferenceToUnsafeThroughTypealias:

lib/Sema/TypeCheckAvailability.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -4258,6 +4258,17 @@ diagnoseDeclUnsafe(const ValueDecl *D, SourceRange R,
42584258
return;
42594259
}
42604260
}
4261+
4262+
// @exclusivity(unchecked) is unsafe.
4263+
if (auto exclusivityAttr =
4264+
var->getAttrs().getAttribute<ExclusivityAttr>()) {
4265+
if (exclusivityAttr->getMode() == ExclusivityAttr::Unchecked) {
4266+
diagnoseUnsafeUse(
4267+
UnsafeUse::forExclusivityUnchecked(var, R.Start,
4268+
Where.getDeclContext()));
4269+
return;
4270+
}
4271+
}
42614272
}
42624273
}
42634274
}

lib/Sema/TypeCheckUnsafe.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ static bool isUnsafeUseInDefinition(const UnsafeUse &use) {
5050
case UnsafeUse::CallToUnsafe:
5151
case UnsafeUse::NonisolatedUnsafe:
5252
case UnsafeUse::UnownedUnsafe:
53+
case UnsafeUse::ExclusivityUnchecked:
5354
case UnsafeUse::UnsafeConformance:
5455
return enclosingContextForUnsafe(use).second;
5556
}
@@ -98,6 +99,7 @@ void swift::diagnoseUnsafeUse(const UnsafeUse &use, bool asNote) {
9899
use.getKind() == UnsafeUse::CallToUnsafe ||
99100
use.getKind() == UnsafeUse::NonisolatedUnsafe ||
100101
use.getKind() == UnsafeUse::UnownedUnsafe ||
102+
use.getKind() == UnsafeUse::ExclusivityUnchecked ||
101103
use.getKind() == UnsafeUse::UnsafeConformance) {
102104
auto [enclosingDecl, _] = enclosingContextForUnsafe(
103105
use.getLocation(), use.getDeclContext());
@@ -178,6 +180,21 @@ void swift::diagnoseUnsafeUse(const UnsafeUse &use, bool asNote) {
178180
return;
179181
}
180182

183+
case UnsafeUse::ExclusivityUnchecked: {
184+
auto var = cast<VarDecl>(use.getDecl());
185+
ASTContext &ctx = var->getASTContext();
186+
ctx.Diags.diagnose(
187+
use.getLocation(),
188+
asNote ? diag::note_reference_exclusivity_unchecked
189+
: diag::reference_exclusivity_unchecked,
190+
var);
191+
if (!asNote) {
192+
var->diagnose(diag::make_enclosing_context_unsafe, var)
193+
.fixItInsert(var->getAttributeInsertionLoc(false), "@unsafe ");
194+
}
195+
return;
196+
}
197+
181198
case UnsafeUse::NonisolatedUnsafe: {
182199
auto decl = use.getDecl();
183200
ASTContext &ctx = decl->getASTContext();

test/Unsafe/unsafe.swift

+13
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,19 @@ struct SuperHolder {
9696
}
9797
}
9898

99+
// -----------------------------------------------------------------------
100+
// Dynamic exclusivity check suppression
101+
// -----------------------------------------------------------------------
102+
class ExclusivityChecking {
103+
@exclusivity(unchecked) var value: Int = 0
104+
105+
// expected-warning@+1{{instance method 'next' involves unsafe code; use '@safe(unchecked)' to assert that the code is memory-safe}}
106+
func next() -> Int {
107+
value += 1 // expected-note{{reference to @exclusivity(unchecked) property 'value' is unsafe}}
108+
return value // expected-note{{reference to @exclusivity(unchecked) property 'value' is unsafe}}
109+
}
110+
}
111+
99112
// -----------------------------------------------------------------------
100113
// Inheritance of @unsafe
101114
// -----------------------------------------------------------------------

0 commit comments

Comments
 (0)