@@ -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 {
@@ -1128,6 +1160,41 @@ struct PartitionOpEvaluator {
11281160 }
11291161 }
11301162 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+ }
11311198 case PartitionOpKind::UnknownPatternError:
11321199 // Begin tracking the specified element in case we have a later use.
11331200 p.trackNewElement (op.getOpArgs ()[0 ]);
@@ -1315,6 +1382,16 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
13151382 // / to our user so that we can emit that error as we process.
13161383 void handleUnknownCodePattern (const PartitionOp &op) const {}
13171384
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+
13181395 // / This is used to determine if an element is actor derived. If we determine
13191396 // / that a region containing such an element is transferred, we emit an error
13201397 // / since actor regions cannot be transferred.
0 commit comments