@@ -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 {
@@ -1128,6 +1160,41 @@ struct PartitionOpEvaluator {
1128
1160
}
1129
1161
}
1130
1162
return ;
1163
+ case PartitionOpKind::RequireInOutSendingAtFunctionExit: {
1164
+ assert (op.getOpArgs ().size () == 1 &&
1165
+ " Require PartitionOp should be passed 1 argument" );
1166
+ assert (p.isTrackingElement (op.getOpArgs ()[0 ]) &&
1167
+ " Require PartitionOp's argument should already be tracked" );
1168
+
1169
+ // First check if the region of our 'inout sending' element has been
1170
+ // transferred. In that case, we emit a special use after free error.
1171
+ if (auto *transferredOperandSet = p.getTransferred (op.getOpArgs ()[0 ])) {
1172
+ for (auto transferredOperand : transferredOperandSet->data ()) {
1173
+ handleInOutSendingNotInitializedAtExitError (op, op.getOpArgs ()[0 ],
1174
+ transferredOperand);
1175
+ }
1176
+ return ;
1177
+ }
1178
+
1179
+ // If we were not transferred, check if our region is actor isolated. If
1180
+ // so, error since we need a disconnected value in the inout parameter.
1181
+ Region inoutSendingRegion = p.getRegion (op.getOpArgs ()[0 ]);
1182
+ auto dynamicRegionIsolation = getIsolationRegionInfo (inoutSendingRegion);
1183
+
1184
+ // If we failed to merge emit an unknown pattern error so we fail.
1185
+ if (!dynamicRegionIsolation) {
1186
+ handleUnknownCodePattern (op);
1187
+ return ;
1188
+ }
1189
+
1190
+ // Otherwise, emit the error if the dynamic region isolation is not
1191
+ // disconnected.
1192
+ if (!dynamicRegionIsolation.isDisconnected ()) {
1193
+ handleInOutSendingNotDisconnectedAtExitError (op, op.getOpArgs ()[0 ],
1194
+ dynamicRegionIsolation);
1195
+ }
1196
+ return ;
1197
+ }
1131
1198
case PartitionOpKind::UnknownPatternError:
1132
1199
// Begin tracking the specified element in case we have a later use.
1133
1200
p.trackNewElement (op.getOpArgs ()[0 ]);
@@ -1315,6 +1382,16 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
1315
1382
// / to our user so that we can emit that error as we process.
1316
1383
void handleUnknownCodePattern (const PartitionOp &op) const {}
1317
1384
1385
+ // / Called if we find an 'inout sending' parameter that is not live at exit.
1386
+ void handleInOutSendingNotInitializedAtExitError (
1387
+ const PartitionOp &op, Element elt, Operand *transferringOp) const {}
1388
+
1389
+ // / Called if we find an 'inout sending' parameter that is live at excit but
1390
+ // / is actor isolated instead of disconnected.
1391
+ void handleInOutSendingNotDisconnectedAtExitError (
1392
+ const PartitionOp &op, Element elt,
1393
+ SILDynamicMergedIsolationInfo actorIsolation) const {}
1394
+
1318
1395
// / This is used to determine if an element is actor derived. If we determine
1319
1396
// / that a region containing such an element is transferred, we emit an error
1320
1397
// / since actor regions cannot be transferred.
0 commit comments