@@ -410,6 +410,15 @@ enum class PartitionOpKind : uint8_t {
410410 // /
411411 // / This is used if we need to reject the program and do not want to assert.
412412 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,
413422};
414423
415424// / PartitionOp represents a primitive operation that can be performed on
@@ -494,6 +503,12 @@ class PartitionOp {
494503 return PartitionOp (PartitionOpKind::UnknownPatternError, elt, sourceInst);
495504 }
496505
506+ static PartitionOp
507+ RequireInOutSendingAtFunctionExit (Element elt, SILInstruction *sourceInst) {
508+ return PartitionOp (PartitionOpKind::RequireInOutSendingAtFunctionExit, elt,
509+ sourceInst);
510+ }
511+
497512 bool operator ==(const PartitionOp &other) const {
498513 return opKind == other.opKind && opArgs == other.opArgs &&
499514 source == other.source ;
@@ -925,6 +940,21 @@ struct PartitionOpEvaluator {
925940 isolationRegionInfo);
926941 }
927942
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+
928958 // / Call isActorDerived on our CRTP subclass.
929959 bool isActorDerived (Element elt) const {
930960 return asImpl ().isActorDerived (elt);
@@ -959,8 +989,10 @@ struct PartitionOpEvaluator {
959989 }
960990
961991 // / 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 ();
964996 }
965997
966998 bool isTaskIsolatedDerived (Element elt) const {
@@ -1150,6 +1182,41 @@ struct PartitionOpEvaluator {
11501182 }
11511183 }
11521184 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+ }
11531220 case PartitionOpKind::UnknownPatternError:
11541221 // Begin tracking the specified element in case we have a later use.
11551222 p.trackNewElement (op.getOpArgs ()[0 ]);
@@ -1337,6 +1404,16 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
13371404 // / to our user so that we can emit that error as we process.
13381405 void handleUnknownCodePattern (const PartitionOp &op) const {}
13391406
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+
13401417 // / This is used to determine if an element is actor derived. If we determine
13411418 // / that a region containing such an element is transferred, we emit an error
13421419 // / since actor regions cannot be transferred.
0 commit comments