@@ -410,6 +410,15 @@ enum class PartitionOpKind : uint8_t {
410
410
// /
411
411
// / This is used if we need to reject the program and do not want to assert.
412
412
UnknownPatternError,
413
+
414
+ // / Require that a 'inout sending' parameter's region is not transferred and
415
+ // / disconnected at a specific function exiting term inst.
416
+ // /
417
+ // / This ensures that if users transfer away an inout sending parameter, the
418
+ // / parameter is reinitialized with a disconnected value.
419
+ // /
420
+ // / Takes one parameter, the inout parameter that we need to check.
421
+ RequireInOutSendingAtFunctionExit,
413
422
};
414
423
415
424
// / PartitionOp represents a primitive operation that can be performed on
@@ -494,6 +503,12 @@ class PartitionOp {
494
503
return PartitionOp (PartitionOpKind::UnknownPatternError, elt, sourceInst);
495
504
}
496
505
506
+ static PartitionOp
507
+ RequireInOutSendingAtFunctionExit (Element elt, SILInstruction *sourceInst) {
508
+ return PartitionOp (PartitionOpKind::RequireInOutSendingAtFunctionExit, elt,
509
+ sourceInst);
510
+ }
511
+
497
512
bool operator ==(const PartitionOp &other) const {
498
513
return opKind == other.opKind && opArgs == other.opArgs &&
499
514
source == other.source ;
@@ -925,6 +940,21 @@ struct PartitionOpEvaluator {
925
940
isolationRegionInfo);
926
941
}
927
942
943
+ // / Call our CRTP subclass.
944
+ void handleInOutSendingNotInitializedAtExitError (
945
+ const PartitionOp &op, Element elt, Operand *transferringOp) const {
946
+ return asImpl ().handleInOutSendingNotInitializedAtExitError (op, elt,
947
+ transferringOp);
948
+ }
949
+
950
+ // / Call our CRTP subclass.
951
+ void handleInOutSendingNotDisconnectedAtExitError (
952
+ const PartitionOp &op, Element elt,
953
+ SILDynamicMergedIsolationInfo isolation) const {
954
+ return asImpl ().handleInOutSendingNotDisconnectedAtExitError (op, elt,
955
+ isolation);
956
+ }
957
+
928
958
// / Call isActorDerived on our CRTP subclass.
929
959
bool isActorDerived (Element elt) const {
930
960
return asImpl ().isActorDerived (elt);
@@ -959,8 +989,10 @@ struct PartitionOpEvaluator {
959
989
}
960
990
961
991
// / Overload of \p getIsolationRegionInfo without an Operand.
962
- SILIsolationInfo getIsolationRegionInfo (Region region) const {
963
- return getIsolationRegionInfo (region, nullptr ).first ;
992
+ SILDynamicMergedIsolationInfo getIsolationRegionInfo (Region region) const {
993
+ if (auto opt = getIsolationRegionInfo (region, nullptr ))
994
+ return opt->first ;
995
+ return SILDynamicMergedIsolationInfo ();
964
996
}
965
997
966
998
bool isTaskIsolatedDerived (Element elt) const {
@@ -1150,6 +1182,41 @@ struct PartitionOpEvaluator {
1150
1182
}
1151
1183
}
1152
1184
return ;
1185
+ case PartitionOpKind::RequireInOutSendingAtFunctionExit: {
1186
+ assert (op.getOpArgs ().size () == 1 &&
1187
+ " Require PartitionOp should be passed 1 argument" );
1188
+ assert (p.isTrackingElement (op.getOpArgs ()[0 ]) &&
1189
+ " Require PartitionOp's argument should already be tracked" );
1190
+
1191
+ // First check if the region of our 'inout sending' element has been
1192
+ // transferred. In that case, we emit a special use after free error.
1193
+ if (auto *transferredOperandSet = p.getTransferred (op.getOpArgs ()[0 ])) {
1194
+ for (auto transferredOperand : transferredOperandSet->data ()) {
1195
+ handleInOutSendingNotInitializedAtExitError (op, op.getOpArgs ()[0 ],
1196
+ transferredOperand);
1197
+ }
1198
+ return ;
1199
+ }
1200
+
1201
+ // If we were not transferred, check if our region is actor isolated. If
1202
+ // so, error since we need a disconnected value in the inout parameter.
1203
+ Region inoutSendingRegion = p.getRegion (op.getOpArgs ()[0 ]);
1204
+ auto dynamicRegionIsolation = getIsolationRegionInfo (inoutSendingRegion);
1205
+
1206
+ // If we failed to merge emit an unknown pattern error so we fail.
1207
+ if (!dynamicRegionIsolation) {
1208
+ handleUnknownCodePattern (op);
1209
+ return ;
1210
+ }
1211
+
1212
+ // Otherwise, emit the error if the dynamic region isolation is not
1213
+ // disconnected.
1214
+ if (!dynamicRegionIsolation.isDisconnected ()) {
1215
+ handleInOutSendingNotDisconnectedAtExitError (op, op.getOpArgs ()[0 ],
1216
+ dynamicRegionIsolation);
1217
+ }
1218
+ return ;
1219
+ }
1153
1220
case PartitionOpKind::UnknownPatternError:
1154
1221
// Begin tracking the specified element in case we have a later use.
1155
1222
p.trackNewElement (op.getOpArgs ()[0 ]);
@@ -1337,6 +1404,16 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
1337
1404
// / to our user so that we can emit that error as we process.
1338
1405
void handleUnknownCodePattern (const PartitionOp &op) const {}
1339
1406
1407
+ // / Called if we find an 'inout sending' parameter that is not live at exit.
1408
+ void handleInOutSendingNotInitializedAtExitError (
1409
+ const PartitionOp &op, Element elt, Operand *transferringOp) const {}
1410
+
1411
+ // / Called if we find an 'inout sending' parameter that is live at excit but
1412
+ // / is actor isolated instead of disconnected.
1413
+ void handleInOutSendingNotDisconnectedAtExitError (
1414
+ const PartitionOp &op, Element elt,
1415
+ SILDynamicMergedIsolationInfo actorIsolation) const {}
1416
+
1340
1417
// / This is used to determine if an element is actor derived. If we determine
1341
1418
// / that a region containing such an element is transferred, we emit an error
1342
1419
// / since actor regions cannot be transferred.
0 commit comments