Skip to content

Commit 87495c6

Browse files
authored
Merge pull request #77900 from gottesmm/rdar127477211
[region-isolation] Perform checking of non-Sendable results using rbi rather than Sema.
2 parents ce09887 + d9f5ef8 commit 87495c6

19 files changed

+522
-126
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,28 @@ NOTE(regionbasedisolation_out_sending_cannot_be_actor_isolated_note_named, none,
10981098
"returning %1 %0 risks causing data races since the caller assumes that %0 can be safely sent to other isolation domains",
10991099
(Identifier, StringRef))
11001100

1101+
//===
1102+
// non-Sendable Results
1103+
1104+
// Example: returning main-actor isolated result to a custom-actor isolated context risks causing data races
1105+
ERROR(rbi_isolation_crossing_result, none,
1106+
"non-Sendable %0-typed result can not be returned from %1 %kind2 to %3 context",
1107+
(Type, ActorIsolation, const ValueDecl *, ActorIsolation))
1108+
ERROR(rbi_isolation_crossing_result_no_decl, none,
1109+
"non-Sendable %0-typed result can not be returned from %1 function to %2 context",
1110+
(Type, ActorIsolation, ActorIsolation))
1111+
NOTE(rbi_non_sendable_nominal,none,
1112+
"%kind0 does not conform to the 'Sendable' protocol",
1113+
(const ValueDecl *))
1114+
NOTE(rbi_nonsendable_function_type,none,
1115+
"a function type must be marked '@Sendable' to conform to 'Sendable'", ())
1116+
NOTE(rbi_add_nominal_sendable_conformance,none,
1117+
"consider making %kind0 conform to the 'Sendable' protocol",
1118+
(const ValueDecl *))
1119+
NOTE(rbi_add_generic_parameter_sendable_conformance,none,
1120+
"consider making generic parameter %0 conform to the 'Sendable' protocol",
1121+
(Type))
1122+
11011123
//===----------------------------------------------------------------------===//
11021124
// MARK: Misc Diagnostics
11031125
//===----------------------------------------------------------------------===//

include/swift/SILOptimizer/Utils/PartitionOpError.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,8 @@ PARTITION_OP_ERROR(InOutSendingNotDisconnectedAtExit)
5959
/// to our user so that we can emit that error as we process.
6060
PARTITION_OP_ERROR(UnknownCodePattern)
6161

62+
/// Used to signify that an isolation crossing function is returning a
63+
/// non-Sendable value.
64+
PARTITION_OP_ERROR(NonSendableIsolationCrossingResult)
65+
6266
#undef PARTITION_OP_ERROR

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,14 @@ enum class PartitionOpKind : uint8_t {
462462
///
463463
/// Takes one parameter, the inout parameter that we need to check.
464464
InOutSendingAtFunctionExit,
465+
466+
/// This is the result of an isolation crossing apply site. We need to emit a
467+
/// special error since we never allow this.
468+
///
469+
/// DISCUSSION: This is actually just a form of "send". Sadly, we can not use
470+
/// "send" directly since "send" expects a SILOperand and these are values. So
471+
/// to work around the API issue, we have to use a different, specific entry.
472+
NonSendableIsolationCrossingResult,
465473
};
466474

467475
/// PartitionOp represents a primitive operation that can be performed on
@@ -574,6 +582,12 @@ class PartitionOp {
574582
sourceInst);
575583
}
576584

585+
static PartitionOp
586+
NonSendableIsolationCrossingResult(Element elt, SILInstruction *sourceInst) {
587+
return PartitionOp(PartitionOpKind::NonSendableIsolationCrossingResult, elt,
588+
sourceInst);
589+
}
590+
577591
bool operator==(const PartitionOp &other) const {
578592
return opKind == other.opKind && opArgs == other.opArgs &&
579593
source == other.source;
@@ -1053,6 +1067,22 @@ class PartitionOpError {
10531067
}
10541068
};
10551069

1070+
struct NonSendableIsolationCrossingResultError {
1071+
const PartitionOp *op;
1072+
1073+
Element returnValueElement;
1074+
1075+
NonSendableIsolationCrossingResultError(const PartitionOp &op,
1076+
Element returnValue)
1077+
: op(&op), returnValueElement(returnValue) {}
1078+
1079+
void print(llvm::raw_ostream &os, RegionAnalysisValueMap &valueMap) const;
1080+
1081+
SWIFT_DEBUG_DUMPER(dump(RegionAnalysisValueMap &valueMap)) {
1082+
print(llvm::dbgs(), valueMap);
1083+
}
1084+
};
1085+
10561086
#define PARTITION_OP_ERROR(NAME) \
10571087
static_assert(std::is_copy_constructible_v<NAME##Error>, \
10581088
#NAME " must be copy constructable");
@@ -1482,8 +1512,15 @@ struct PartitionOpEvaluator {
14821512

14831513
// Then emit an unknown code pattern error.
14841514
return handleError(UnknownCodePatternError(op));
1515+
case PartitionOpKind::NonSendableIsolationCrossingResult:
1516+
// Grab the dynamic dataflow isolation information for our element's
1517+
// region.
1518+
Region region = p.getRegion(op.getOpArgs()[0]);
1519+
1520+
// Then emit the error.
1521+
return handleError(
1522+
NonSendableIsolationCrossingResultError(op, op.getOpArgs()[0]));
14851523
}
1486-
14871524
llvm_unreachable("Covered switch isn't covered?!");
14881525
}
14891526

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,12 @@ struct PartitionOpBuilder {
15261526
PartitionOp::UnknownPatternError(lookupValueID(value), currentInst));
15271527
}
15281528

1529+
void addNonSendableIsolationCrossingResultError(SILValue value) {
1530+
currentInstPartitionOps.emplace_back(
1531+
PartitionOp::NonSendableIsolationCrossingResult(lookupValueID(value),
1532+
currentInst));
1533+
}
1534+
15291535
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
15301536

15311537
void print(llvm::raw_ostream &os) const;
@@ -2394,14 +2400,58 @@ class PartitionOpTranslator {
23942400
handleSILOperands(applySite.getOperandsWithoutIndirectResults());
23952401
}
23962402

2397-
// non-sendable results can't be returned from cross-isolation calls without
2398-
// a diagnostic emitted elsewhere. Here, give them a fresh value for better
2399-
// diagnostics hereafter
2403+
// Create a new assign fresh for each one of our values and unless our
2404+
// return value is sending, emit an extra error bit on the results that are
2405+
// non-Sendable.
24002406
SmallVector<SILValue, 8> applyResults;
24012407
getApplyResults(*applySite, applyResults);
2402-
for (auto result : applyResults)
2403-
if (auto value = tryToTrackValue(result))
2408+
2409+
auto substCalleeType = applySite.getSubstCalleeType();
2410+
2411+
// Today, all values in result info are sending or none are. So this is a
2412+
// safe to check that we have a sending result. In the future if we allow
2413+
// for sending to vary, then this code will need to be updated to vary with
2414+
// each result.
2415+
auto results = substCalleeType->getResults();
2416+
auto *applyExpr = applySite->getLoc().getAsASTNode<ApplyExpr>();
2417+
2418+
// We only emit the error if we do not have a sending result and if our
2419+
// callee isn't nonisolated.
2420+
//
2421+
// DISCUSSION: If our callee is non-isolated, we know that the value must
2422+
// have been returned as a non-sent disconnected value. The reason why this
2423+
// is different from a sending result is that the result may be part of the
2424+
// region of the operands while the sending result will not be. In either
2425+
// case though, we do not want to emit the error.
2426+
bool emitIsolationCrossingResultError =
2427+
(results.empty() || !results[0].hasOption(SILResultInfo::IsSending)) &&
2428+
// We have to check if we actually have an apply expr since we may not
2429+
// have one if we are processing a SIL test case since SIL does not have
2430+
// locations (which is how we grab our AST information).
2431+
!(applyExpr && applyExpr->getIsolationCrossing()
2432+
->getCalleeIsolation()
2433+
.isNonisolated());
2434+
2435+
for (auto result : applyResults) {
2436+
if (auto value = tryToTrackValue(result)) {
24042437
builder.addAssignFresh(value->getRepresentative().getValue());
2438+
if (emitIsolationCrossingResultError)
2439+
builder.addNonSendableIsolationCrossingResultError(
2440+
value->getRepresentative().getValue());
2441+
}
2442+
}
2443+
2444+
// If we are supposed to emit isolation crossing errors, go through our
2445+
// parameters and add the error on any indirect results that are
2446+
// non-Sendable.
2447+
if (emitIsolationCrossingResultError) {
2448+
for (auto result : applySite.getIndirectSILResults()) {
2449+
if (auto value = tryToTrackValue(result)) {
2450+
builder.addNonSendableIsolationCrossingResultError(
2451+
value->getRepresentative().getValue());
2452+
}
2453+
}
2454+
}
24052455
}
24062456

24072457
template <typename DestValues>

0 commit comments

Comments
 (0)