Skip to content

Commit fcedb0b

Browse files
authored
Merge pull request #81125 from DougGregor/unsafe-call-effects-6.2
[6.2] [Strict memory safety] Provide argument-specific diagnostics for calls
2 parents 0afd6b1 + 428da5e commit fcedb0b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+479
-190
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8295,6 +8295,15 @@ NOTE(note_reference_to_unsafe_decl,none,
82958295
NOTE(note_reference_to_unsafe_typed_decl,none,
82968296
"%select{reference|call}0 to %kind1 involves unsafe type %2",
82978297
(bool, const ValueDecl *, Type))
8298+
NOTE(note_unsafe_call_decl_argument_named,none,
8299+
"argument %1 in call to %kindbase0 has unsafe type %2",
8300+
(const ValueDecl *, Identifier, Type))
8301+
NOTE(note_unsafe_call_decl_argument_indexed,none,
8302+
"argument #%1 in call to %kindbase0 has unsafe type %2",
8303+
(const ValueDecl *, unsigned, Type))
8304+
NOTE(note_unsafe_call_argument_indexed,none,
8305+
"argument #%0 in call has unsafe type %1",
8306+
(unsigned, Type))
82988307
NOTE(note_reference_to_unsafe_through_typealias,none,
82998308
"reference to %kind0 whose underlying type involves unsafe type %1",
83008309
(const ValueDecl *, Type))
@@ -8355,9 +8364,9 @@ GROUPED_WARNING(unsafe_without_unsafe,StrictMemorySafety,none,
83558364
"expression uses unsafe constructs but is not marked with 'unsafe'", ())
83568365
GROUPED_WARNING(for_unsafe_without_unsafe,StrictMemorySafety,none,
83578366
"for-in loop uses unsafe constructs but is not marked with 'unsafe'", ())
8358-
GROUPED_WARNING(no_unsafe_in_unsafe,StrictMemorySafety,none,
8367+
WARNING(no_unsafe_in_unsafe,none,
83598368
"no unsafe operations occur within 'unsafe' expression", ())
8360-
GROUPED_WARNING(no_unsafe_in_unsafe_for,StrictMemorySafety,none,
8369+
WARNING(no_unsafe_in_unsafe_for,none,
83618370
"no unsafe operations occur within 'unsafe' for-in loop", ())
83628371
NOTE(make_subclass_unsafe,none,
83638372
"make class %0 '@unsafe' to allow unsafe overrides of safe superclass "

include/swift/AST/UnsafeUse.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class UnsafeUse {
5353
ReferenceToUnsafeThroughTypealias,
5454
/// A call to an unsafe declaration.
5555
CallToUnsafe,
56+
/// An unsafe argument in a call.
57+
CallArgument,
5658
/// A @preconcurrency import.
5759
PreconcurrencyImport,
5860
/// A use of withoutActuallyEscaping that lacks enforcement that the
@@ -91,6 +93,15 @@ class UnsafeUse {
9193

9294
MakeTemporarilyEscapableExpr *temporarilyEscaping;
9395

96+
struct {
97+
Expr *call;
98+
const Decl *calleeDecl;
99+
TypeBase *paramType;
100+
const void *argumentName;
101+
unsigned argumentIndex;
102+
Expr *argument;
103+
} callArgument;
104+
94105
const ImportDecl *importDecl;
95106
} storage;
96107

@@ -201,6 +212,19 @@ class UnsafeUse {
201212
decl, type, location);
202213
}
203214

215+
static UnsafeUse forCallArgument(
216+
Expr *call, const Decl *calleeDecl, Type paramType,
217+
Identifier argumentName, unsigned argumentIndex, Expr *argument) {
218+
UnsafeUse result(CallArgument);
219+
result.storage.callArgument.call = call;
220+
result.storage.callArgument.calleeDecl = calleeDecl;
221+
result.storage.callArgument.paramType = paramType.getPointer();
222+
result.storage.callArgument.argumentName = argumentName.getAsOpaquePointer();
223+
result.storage.callArgument.argumentIndex = argumentIndex;
224+
result.storage.callArgument.argument = argument;
225+
return result;
226+
}
227+
204228
static UnsafeUse forTemporarilyEscaping(MakeTemporarilyEscapableExpr *expr) {
205229
UnsafeUse result(TemporarilyEscaping);
206230
result.storage.temporarilyEscaping = expr;
@@ -242,6 +266,9 @@ class UnsafeUse {
242266
return SourceLoc(
243267
llvm::SMLoc::getFromPointer((const char *)storage.entity.location));
244268

269+
case CallArgument:
270+
return storage.callArgument.call->getLoc();
271+
245272
case TemporarilyEscaping:
246273
return storage.temporarilyEscaping->getLoc();
247274

@@ -257,6 +284,7 @@ class UnsafeUse {
257284
case Witness:
258285
case TemporarilyEscaping:
259286
case PreconcurrencyImport:
287+
case CallArgument:
260288
// Cannot replace location.
261289
return;
262290

@@ -298,6 +326,9 @@ class UnsafeUse {
298326
case CallToUnsafe:
299327
return storage.entity.decl;
300328

329+
case CallArgument:
330+
return storage.callArgument.calleeDecl;
331+
301332
case UnsafeConformance:
302333
case TemporarilyEscaping:
303334
return nullptr;
@@ -330,6 +361,7 @@ class UnsafeUse {
330361
case ReferenceToUnsafeThroughTypealias:
331362
case ReferenceToUnsafeStorage:
332363
case CallToUnsafe:
364+
case CallArgument:
333365
case UnsafeConformance:
334366
case PreconcurrencyImport:
335367
case TemporarilyEscaping:
@@ -360,6 +392,9 @@ class UnsafeUse {
360392
case CallToUnsafe:
361393
return storage.entity.type;
362394

395+
case CallArgument:
396+
return storage.callArgument.paramType;
397+
363398
case TemporarilyEscaping:
364399
return storage.temporarilyEscaping->getOpaqueValue()->getType();
365400
}
@@ -386,11 +421,24 @@ class UnsafeUse {
386421
case ReferenceToUnsafeStorage:
387422
case ReferenceToUnsafeThroughTypealias:
388423
case CallToUnsafe:
424+
case CallArgument:
389425
case TemporarilyEscaping:
390426
case PreconcurrencyImport:
391427
return ProtocolConformanceRef::forInvalid();
392428
}
393429
}
430+
431+
/// Get information about the call argument.
432+
///
433+
/// Produces the argument name, argument index, and argument expression for
434+
/// a unsafe use describing a call argument.
435+
std::tuple<Identifier, unsigned, Expr *> getCallArgument() const {
436+
assert(getKind() == CallArgument);
437+
return std::make_tuple(
438+
Identifier::getFromOpaquePointer(storage.callArgument.argumentName),
439+
storage.callArgument.argumentIndex,
440+
storage.callArgument.argument);
441+
}
394442
};
395443

396444
} // end namespace swift

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,6 +2699,7 @@ diagnoseDeclUnsafe(ConcreteDeclRef declRef, SourceRange R,
26992699

27002700
SourceLoc diagLoc = call ? call->getLoc() : R.Start;
27012701
enumerateUnsafeUses(declRef, diagLoc, call != nullptr,
2702+
/*skipTypeCheck=*/false,
27022703
[&](UnsafeUse unsafeUse) {
27032704
unsafeUses->push_back(unsafeUse);
27042705
return false;

0 commit comments

Comments
 (0)