@@ -391,7 +391,17 @@ struct MoveOnlyChecker {
391
391
// / [noimplicitcopy]. If we find one that does not fit a pattern that we
392
392
// / understand, emit an error diagnostic telling the programmer that the move
393
393
// / checker did not know how to recognize this code pattern.
394
- void searchForCandidateMarkMustChecks ();
394
+ // /
395
+ // / Returns true if we emitted a diagnostic. Returns false otherwise.
396
+ bool searchForCandidateMarkMustChecks ();
397
+
398
+ // / After we have emitted a diagnostic, we need to clean up the instruction
399
+ // / stream by converting /all/ copies of move only typed things to use
400
+ // / explicit_copy_value so that we maintain the SIL invariant that in
401
+ // / canonical SIL move only types are not copied by normal copies.
402
+ // /
403
+ // / Returns true if we actually changed any instructions.
404
+ void cleanupAfterEmittingDiagnostic ();
395
405
396
406
// / Emits an error diagnostic for \p markedValue.
397
407
void performObjectCheck (MarkMustCheckInst *markedValue);
@@ -1334,7 +1344,44 @@ bool GlobalDataflow::compute() {
1334
1344
// MARK: Main Pass Implementation
1335
1345
// ===----------------------------------------------------------------------===//
1336
1346
1337
- void MoveOnlyChecker::searchForCandidateMarkMustChecks () {
1347
+ void MoveOnlyChecker::cleanupAfterEmittingDiagnostic () {
1348
+ for (auto &block : *fn) {
1349
+ for (auto ii = block.begin (), ie = block.end (); ii != ie;) {
1350
+ auto *inst = &*ii;
1351
+ ++ii;
1352
+
1353
+ // Convert load [copy] -> load_borrow + explicit_copy_value.
1354
+ if (auto *li = dyn_cast<LoadInst>(inst)) {
1355
+ if (li->getOwnershipQualifier () == LoadOwnershipQualifier::Copy) {
1356
+ SILBuilderWithScope builder (li);
1357
+ auto *lbi = builder.createLoadBorrow (li->getLoc (), li->getOperand ());
1358
+ auto *cvi = builder.createExplicitCopyValue (li->getLoc (), lbi);
1359
+ builder.createEndBorrow (li->getLoc (), lbi);
1360
+ li->replaceAllUsesWith (cvi);
1361
+ li->eraseFromParent ();
1362
+ changed = true ;
1363
+ }
1364
+ }
1365
+
1366
+ // Convert copy_addr !take of src to its explicit value form so we don't
1367
+ // error.
1368
+ if (auto *copyAddr = dyn_cast<CopyAddrInst>(inst)) {
1369
+ if (!copyAddr->isTakeOfSrc ()) {
1370
+ SILBuilderWithScope builder (copyAddr);
1371
+ builder.createExplicitCopyAddr (
1372
+ copyAddr->getLoc (), copyAddr->getSrc (), copyAddr->getDest (),
1373
+ IsTake_t (copyAddr->isTakeOfSrc ()),
1374
+ IsInitialization_t (copyAddr->isInitializationOfDest ()));
1375
+ copyAddr->eraseFromParent ();
1376
+ changed = true ;
1377
+ }
1378
+ }
1379
+ }
1380
+ }
1381
+ }
1382
+
1383
+ bool MoveOnlyChecker::searchForCandidateMarkMustChecks () {
1384
+ bool emittedDiagnostic = false ;
1338
1385
for (auto &block : *fn) {
1339
1386
for (auto ii = block.begin (), ie = block.end (); ii != ie;) {
1340
1387
auto *mmci = dyn_cast<MarkMustCheckInst>(&*ii);
@@ -1351,6 +1398,7 @@ void MoveOnlyChecker::searchForCandidateMarkMustChecks() {
1351
1398
llvm::dbgs ()
1352
1399
<< " Early emitting diagnostic for unsupported alloc box!\n " );
1353
1400
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic (mmci);
1401
+ emittedDiagnostic = true ;
1354
1402
continue ;
1355
1403
}
1356
1404
@@ -1360,6 +1408,7 @@ void MoveOnlyChecker::searchForCandidateMarkMustChecks() {
1360
1408
llvm::dbgs ()
1361
1409
<< " Early emitting diagnostic for unsupported alloc box!\n " );
1362
1410
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic (mmci);
1411
+ emittedDiagnostic = true ;
1363
1412
continue ;
1364
1413
}
1365
1414
}
@@ -1368,6 +1417,7 @@ void MoveOnlyChecker::searchForCandidateMarkMustChecks() {
1368
1417
moveIntroducersToProcess.insert (mmci);
1369
1418
}
1370
1419
}
1420
+ return emittedDiagnostic;
1371
1421
}
1372
1422
1373
1423
bool MoveOnlyChecker::performSingleCheck (MarkMustCheckInst *markedAddress) {
@@ -1566,15 +1616,18 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
1566
1616
bool MoveOnlyChecker::check () {
1567
1617
// First search for candidates to process and emit diagnostics on any
1568
1618
// mark_must_check [noimplicitcopy] we didn't recognize.
1569
- searchForCandidateMarkMustChecks ();
1619
+ bool emittedDiagnostic = searchForCandidateMarkMustChecks ();
1570
1620
1571
1621
// If we didn't find any introducers to check, just return changed.
1572
1622
//
1573
1623
// NOTE: changed /can/ be true here if we had any mark_must_check
1574
1624
// [noimplicitcopy] that we didn't understand and emitting a diagnostic upon
1575
1625
// and then deleting.
1576
- if (moveIntroducersToProcess.empty ())
1626
+ if (moveIntroducersToProcess.empty ()) {
1627
+ if (emittedDiagnostic)
1628
+ cleanupAfterEmittingDiagnostic ();
1577
1629
return changed;
1630
+ }
1578
1631
1579
1632
for (auto *markedValue : moveIntroducersToProcess) {
1580
1633
LLVM_DEBUG (llvm::dbgs () << " Visiting: " << *markedValue);
@@ -1587,7 +1640,7 @@ bool MoveOnlyChecker::check() {
1587
1640
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic (markedValue);
1588
1641
}
1589
1642
}
1590
- bool emittedDiagnostic = diagnosticEmitter.emittedAnyDiagnostics ();
1643
+ emittedDiagnostic = diagnosticEmitter.emittedAnyDiagnostics ();
1591
1644
1592
1645
// Ok, now that we have performed our checks, we need to eliminate all mark
1593
1646
// must check inst since it is invalid for these to be in canonical SIL and
@@ -1608,40 +1661,7 @@ bool MoveOnlyChecker::check() {
1608
1661
// It is also ok that we use a little more compile time and go over the
1609
1662
// function again, since we are going to fail the compilation and not codegen.
1610
1663
if (emittedDiagnostic) {
1611
- for (auto &block : *fn) {
1612
- for (auto ii = block.begin (), ie = block.end (); ii != ie;) {
1613
- auto *inst = &*ii;
1614
- ++ii;
1615
-
1616
- // Convert load [copy] -> load_borrow + explicit_copy_value.
1617
- if (auto *li = dyn_cast<LoadInst>(inst)) {
1618
- if (li->getOwnershipQualifier () == LoadOwnershipQualifier::Copy) {
1619
- SILBuilderWithScope builder (li);
1620
- auto *lbi =
1621
- builder.createLoadBorrow (li->getLoc (), li->getOperand ());
1622
- auto *cvi = builder.createExplicitCopyValue (li->getLoc (), lbi);
1623
- builder.createEndBorrow (li->getLoc (), lbi);
1624
- li->replaceAllUsesWith (cvi);
1625
- li->eraseFromParent ();
1626
- changed = true ;
1627
- }
1628
- }
1629
-
1630
- // Convert copy_addr !take of src to its explicit value form so we don't
1631
- // error.
1632
- if (auto *copyAddr = dyn_cast<CopyAddrInst>(inst)) {
1633
- if (!copyAddr->isTakeOfSrc ()) {
1634
- SILBuilderWithScope builder (copyAddr);
1635
- builder.createExplicitCopyAddr (
1636
- copyAddr->getLoc (), copyAddr->getSrc (), copyAddr->getDest (),
1637
- IsTake_t (copyAddr->isTakeOfSrc ()),
1638
- IsInitialization_t (copyAddr->isInitializationOfDest ()));
1639
- copyAddr->eraseFromParent ();
1640
- changed = true ;
1641
- }
1642
- }
1643
- }
1644
- }
1664
+ cleanupAfterEmittingDiagnostic ();
1645
1665
}
1646
1666
1647
1667
return changed;
0 commit comments