mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
add an experimental feature DeferSendableChecking to defer the sendable checking of some sites. For now, only diagnostics corresponding to non-sendable arguments passed to calls with unsatisfied isolation are deferred. A SIL pass SendNonSendable is added to emit the deferred diagnostics, and ApplyExpr is appropriately enriched to make that deferral possible.
This commit is contained in:
@@ -4625,6 +4625,41 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// ApplyIsolationCrossing records the source and target of an isolation crossing
|
||||
// within an ApplyExpr. In particular, it stores the isolation of the caller
|
||||
// and the callee of the ApplyExpr, to be used for inserting implicit actor
|
||||
// hops for implicitly async functions and to be used for diagnosing potential
|
||||
// data races that could arise when non-Sendable values are passed to calls
|
||||
// that cross isolation domains.
|
||||
struct ApplyIsolationCrossing {
|
||||
ActorIsolation CallerIsolation;
|
||||
ActorIsolation CalleeIsolation;
|
||||
|
||||
ApplyIsolationCrossing()
|
||||
: CallerIsolation(ActorIsolation::forUnspecified()),
|
||||
CalleeIsolation(ActorIsolation::forUnspecified()) {}
|
||||
|
||||
ApplyIsolationCrossing(ActorIsolation CallerIsolation,
|
||||
ActorIsolation CalleeIsolation)
|
||||
: CallerIsolation(CallerIsolation), CalleeIsolation(CalleeIsolation) {}
|
||||
|
||||
// If the callee is not actor isolated, then this crossing exits isolation.
|
||||
// This method returns true iff this crossing exits isolation.
|
||||
bool exitsIsolation() const { return !CalleeIsolation.isActorIsolated(); }
|
||||
|
||||
// Whether to use the isolation of the caller or callee for generating
|
||||
// informative diagnostics depends on whether this crossing is an exit.
|
||||
// In particular, we tend to use the caller isolation for diagnostics,
|
||||
// but if this crossing is an exit from isolation then the callee isolation
|
||||
// is not very informative, so we use the caller isolation instead.
|
||||
ActorIsolation getDiagnoseIsolation() const {
|
||||
return exitsIsolation() ? CallerIsolation : CalleeIsolation;
|
||||
}
|
||||
|
||||
ActorIsolation getCallerIsolation() const { return CallerIsolation; }
|
||||
ActorIsolation getCalleeIsolation() const {return CalleeIsolation; }
|
||||
};
|
||||
|
||||
/// ApplyExpr - Superclass of various function calls, which apply an argument to
|
||||
/// a function to get a result.
|
||||
class ApplyExpr : public Expr {
|
||||
@@ -4634,13 +4669,14 @@ class ApplyExpr : public Expr {
|
||||
/// The list of arguments to call the function with.
|
||||
ArgumentList *ArgList;
|
||||
|
||||
ActorIsolation implicitActorHopTarget;
|
||||
// If this apply crosses isolation boundaries, record the callee and caller
|
||||
// isolations in this struct.
|
||||
llvm::Optional<ApplyIsolationCrossing> IsolationCrossing;
|
||||
|
||||
protected:
|
||||
ApplyExpr(ExprKind kind, Expr *fn, ArgumentList *argList, bool implicit,
|
||||
Type ty = Type())
|
||||
: Expr(kind, implicit, ty), Fn(fn), ArgList(argList),
|
||||
implicitActorHopTarget(ActorIsolation::forUnspecified()) {
|
||||
: Expr(kind, implicit, ty), Fn(fn), ArgList(argList) {
|
||||
assert(ArgList);
|
||||
assert(classof((Expr*)this) && "ApplyExpr::classof out of date");
|
||||
Bits.ApplyExpr.ThrowsIsSet = false;
|
||||
@@ -4687,6 +4723,21 @@ public:
|
||||
Bits.ApplyExpr.NoAsync = noAsync;
|
||||
}
|
||||
|
||||
// Return the optionally stored ApplyIsolationCrossing instance - set iff this
|
||||
// ApplyExpr crosses isolation domains
|
||||
const llvm::Optional<ApplyIsolationCrossing> getIsolationCrossing() const {
|
||||
return IsolationCrossing;
|
||||
}
|
||||
|
||||
// Record that this apply crosses isolation domains, noting the isolation of
|
||||
// the caller and callee by storing them into the IsolationCrossing field
|
||||
void setIsolationCrossing(
|
||||
ActorIsolation callerIsolation, ActorIsolation calleeIsolation) {
|
||||
assert(!IsolationCrossing.has_value()
|
||||
&& "IsolationCrossing should not be set twice");
|
||||
IsolationCrossing = {callerIsolation, calleeIsolation};
|
||||
}
|
||||
|
||||
/// Is this application _implicitly_ required to be an async call?
|
||||
/// That is, does it need to be guarded by hop_to_executor.
|
||||
/// Note that this is _not_ a check for whether the callee is async!
|
||||
@@ -4710,13 +4761,20 @@ public:
|
||||
if (!Bits.ApplyExpr.ImplicitlyAsync)
|
||||
return llvm::None;
|
||||
|
||||
return implicitActorHopTarget;
|
||||
auto isolationCrossing = getIsolationCrossing();
|
||||
assert(isolationCrossing.has_value()
|
||||
&& "Implicitly async ApplyExprs should always "
|
||||
"have had IsolationCrossing set");
|
||||
|
||||
return isolationCrossing.value().CalleeIsolation;
|
||||
}
|
||||
|
||||
/// Note that this application is implicitly async and set the target.
|
||||
void setImplicitlyAsync(ActorIsolation target) {
|
||||
assert(getIsolationCrossing().has_value()
|
||||
&& "ApplyExprs should always call setIsolationCrossing"
|
||||
" before setImplicitlyAsync");
|
||||
Bits.ApplyExpr.ImplicitlyAsync = true;
|
||||
implicitActorHopTarget = target;
|
||||
}
|
||||
|
||||
/// Is this application _implicitly_ required to be a throwing call?
|
||||
|
||||
@@ -217,6 +217,9 @@ EXPERIMENTAL_FEATURE(BuiltinModule, true)
|
||||
// Enable strict concurrency.
|
||||
EXPERIMENTAL_FEATURE(StrictConcurrency, true)
|
||||
|
||||
/// Defer Sendable checking to SIL diagnostic phase.
|
||||
EXPERIMENTAL_FEATURE(DeferredSendableChecking, false)
|
||||
|
||||
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
|
||||
#undef EXPERIMENTAL_FEATURE
|
||||
#undef UPCOMING_FEATURE
|
||||
|
||||
@@ -365,6 +365,8 @@ PASS(TempRValueOpt, "temp-rvalue-opt",
|
||||
"Remove short-lived immutable temporary copies")
|
||||
PASS(IRGenPrepare, "irgen-prepare",
|
||||
"Cleanup SIL in preparation for IRGen")
|
||||
PASS(SendNonSendable, "send-non-sendable",
|
||||
"Checks calls that send non-sendable values between isolation domains")
|
||||
PASS(SILGenCleanup, "silgen-cleanup",
|
||||
"Cleanup SIL in preparation for diagnostics")
|
||||
PASS(SILCombine, "sil-combine",
|
||||
|
||||
Reference in New Issue
Block a user