@@ -400,6 +400,16 @@ enum class PartitionOpKind : uint8_t {
400
400
401
401
// / Require the region of a value to be non-transferred, takes one arg.
402
402
Require,
403
+
404
+ // / Emit an error saying that the given instruction was not understood for
405
+ // / some reason and that a bug should be filed. It expects some sort of
406
+ // / Element number since in most cases we need to define a value for later
407
+ // / potential uses of the value (e.x.: an alloc_stack that we emit an unknown
408
+ // / pattern error will have later uses that will use the value... without
409
+ // / defining the value, the dataflow will assert).
410
+ // /
411
+ // / This is used if we need to reject the program and do not want to assert.
412
+ UnknownPatternError,
403
413
};
404
414
405
415
// / PartitionOp represents a primitive operation that can be performed on
@@ -444,6 +454,9 @@ class PartitionOp {
444
454
" Transfer needs a sourceInst" );
445
455
}
446
456
457
+ PartitionOp (PartitionOpKind opKind, SILInstruction *sourceInst)
458
+ : opKind(opKind), opArgs(), source(sourceInst) {}
459
+
447
460
friend class Partition ;
448
461
449
462
public:
@@ -476,6 +489,11 @@ class PartitionOp {
476
489
return PartitionOp (PartitionOpKind::Require, tgt, sourceInst);
477
490
}
478
491
492
+ static PartitionOp UnknownPatternError (Element elt,
493
+ SILInstruction *sourceInst) {
494
+ return PartitionOp (PartitionOpKind::UnknownPatternError, elt, sourceInst);
495
+ }
496
+
479
497
bool operator ==(const PartitionOp &other) const {
480
498
return opKind == other.opKind && opArgs == other.opArgs &&
481
499
source == other.source ;
@@ -881,6 +899,11 @@ struct PartitionOpEvaluator {
881
899
return asImpl ().shouldEmitVerboseLogging ();
882
900
}
883
901
902
+ // / Call handleUnknownCodePattern on our CRTP subclass.
903
+ void handleUnknownCodePattern (const PartitionOp &op) const {
904
+ return asImpl ().handleUnknownCodePattern (op);
905
+ }
906
+
884
907
// / Call handleLocalUseAfterTransfer on our CRTP subclass.
885
908
void handleLocalUseAfterTransfer (const PartitionOp &op, Element elt,
886
909
Operand *transferringOp) const {
@@ -1119,6 +1142,13 @@ struct PartitionOpEvaluator {
1119
1142
}
1120
1143
}
1121
1144
return ;
1145
+ case PartitionOpKind::UnknownPatternError:
1146
+ // Begin tracking the specified element in case we have a later use.
1147
+ p.trackNewElement (op.getOpArgs ()[0 ]);
1148
+
1149
+ // Then emit an unknown code pattern error.
1150
+ handleUnknownCodePattern (op);
1151
+ return ;
1122
1152
}
1123
1153
1124
1154
llvm_unreachable (" Covered switch isn't covered?!" );
@@ -1259,6 +1289,13 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
1259
1289
const PartitionOp &op, Element elt, Element otherElement,
1260
1290
SILDynamicMergedIsolationInfo isolationRegionInfo) const {}
1261
1291
1292
+ // / Used to signify an "unknown code pattern" has occured while performing
1293
+ // / dataflow.
1294
+ // /
1295
+ // / DISCUSSION: Our dataflow cannot emit errors itself so this is a callback
1296
+ // / to our user so that we can emit that error as we process.
1297
+ void handleUnknownCodePattern (const PartitionOp &op) const {}
1298
+
1262
1299
// / This is used to determine if an element is actor derived. If we determine
1263
1300
// / that a region containing such an element is transferred, we emit an error
1264
1301
// / since actor regions cannot be transferred.
0 commit comments