Skip to content

Commit 771cb35

Browse files
authored
Merge pull request #81120 from DougGregor/unsafe-call-effects
[Strict memory safety] Provide argument-specific diagnostics for calls
2 parents bb84882 + 1b94c3b commit 771cb35

Some content is hidden

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

47 files changed

+484
-209
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8341,6 +8341,15 @@ NOTE(note_reference_to_unsafe_decl,none,
83418341
NOTE(note_reference_to_unsafe_typed_decl,none,
83428342
"%select{reference|call}0 to %kind1 involves unsafe type %2",
83438343
(bool, const ValueDecl *, Type))
8344+
NOTE(note_unsafe_call_decl_argument_named,none,
8345+
"argument %1 in call to %kindbase0 has unsafe type %2",
8346+
(const ValueDecl *, Identifier, Type))
8347+
NOTE(note_unsafe_call_decl_argument_indexed,none,
8348+
"argument #%1 in call to %kindbase0 has unsafe type %2",
8349+
(const ValueDecl *, unsigned, Type))
8350+
NOTE(note_unsafe_call_argument_indexed,none,
8351+
"argument #%0 in call has unsafe type %1",
8352+
(unsigned, Type))
83448353
NOTE(note_reference_to_unsafe_through_typealias,none,
83458354
"reference to %kind0 whose underlying type involves unsafe type %1",
83468355
(const ValueDecl *, Type))
@@ -8402,9 +8411,9 @@ GROUPED_WARNING(unsafe_without_unsafe,StrictMemorySafety,none,
84028411
"expression uses unsafe constructs but is not marked with 'unsafe'", ())
84038412
GROUPED_WARNING(for_unsafe_without_unsafe,StrictMemorySafety,none,
84048413
"for-in loop uses unsafe constructs but is not marked with 'unsafe'", ())
8405-
GROUPED_WARNING(no_unsafe_in_unsafe,StrictMemorySafety,none,
8414+
WARNING(no_unsafe_in_unsafe,none,
84068415
"no unsafe operations occur within 'unsafe' expression", ())
8407-
GROUPED_WARNING(no_unsafe_in_unsafe_for,StrictMemorySafety,none,
8416+
WARNING(no_unsafe_in_unsafe_for,none,
84088417
"no unsafe operations occur within 'unsafe' for-in loop", ())
84098418
NOTE(make_subclass_unsafe,none,
84108419
"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/CSApply.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8149,7 +8149,7 @@ Expr *ExprRewriter::convertLiteralInPlace(
81498149
Diag<> brokenProtocolDiag, Diag<> brokenBuiltinProtocolDiag) {
81508150
// If coercing a literal to an unresolved type, we don't try to look up the
81518151
// witness members, just do it.
8152-
if (type->is<UnresolvedType>()) {
8152+
if (type->is<UnresolvedType>() || type->is<ErrorType>()) {
81538153
cs.setType(literal, type);
81548154
return literal;
81558155
}

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)