@@ -292,6 +292,7 @@ struct UseState {
292
292
llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > livenessUses;
293
293
llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > borrows;
294
294
llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > takeInsts;
295
+ llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > copyInsts;
295
296
llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > initInsts;
296
297
llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > reinitInsts;
297
298
@@ -301,6 +302,7 @@ struct UseState {
301
302
destroys.clear ();
302
303
livenessUses.clear ();
303
304
borrows.clear ();
305
+ copyInsts.clear ();
304
306
takeInsts.clear ();
305
307
initInsts.clear ();
306
308
reinitInsts.clear ();
@@ -552,6 +554,9 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
552
554
// At this point, we have handled all of the non-loadTakeOrCopy/consuming
553
555
// uses.
554
556
if (auto *copyAddr = dyn_cast<CopyAddrInst>(user)) {
557
+ assert (op->getOperandNumber () == CopyAddrInst::Src &&
558
+ " Should have dest above in memInstMust{Rei,I}nitialize" );
559
+
555
560
if (markedValue->getCheckKind () == MarkMustCheckInst::CheckKind::NoCopy) {
556
561
LLVM_DEBUG (llvm::dbgs ()
557
562
<< " Found mark must check [nocopy] error: " << *user);
@@ -564,8 +569,13 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
564
569
if (!leafRange)
565
570
return false ;
566
571
567
- LLVM_DEBUG (llvm::dbgs () << " Found take: " << *user);
568
- useState.takeInsts .insert ({user, *leafRange});
572
+ if (copyAddr->isTakeOfSrc ()) {
573
+ LLVM_DEBUG (llvm::dbgs () << " Found take: " << *user);
574
+ useState.takeInsts .insert ({user, *leafRange});
575
+ } else {
576
+ LLVM_DEBUG (llvm::dbgs () << " Found copy: " << *user);
577
+ useState.copyInsts .insert ({user, *leafRange});
578
+ }
569
579
return true ;
570
580
}
571
581
@@ -637,7 +647,7 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
637
647
}
638
648
639
649
// Then if we had any final consuming uses, mark that this liveness use is
640
- // a take and if not, mark this as a borrow.
650
+ // a take/copy and if not, mark this as a borrow.
641
651
auto leafRange = TypeTreeLeafTypeRange::get (op->get (), getRootAddress ());
642
652
if (!leafRange)
643
653
return false ;
@@ -652,14 +662,23 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
652
662
653
663
useState.borrows .insert ({user, *leafRange});
654
664
} else {
655
- LLVM_DEBUG (llvm::dbgs () << " Found take inst: " << *user);
656
- useState.takeInsts .insert ({user, *leafRange});
665
+ // If we had a load [copy], store this into the copy list. These are the
666
+ // things that we must merge into destroy_addr or reinits after we are
667
+ // done checking. The load [take] are already complete and good to go.
668
+ if (li->getOwnershipQualifier () == LoadOwnershipQualifier::Take) {
669
+ LLVM_DEBUG (llvm::dbgs () << " Found take inst: " << *user);
670
+ useState.takeInsts .insert ({user, *leafRange});
671
+ } else {
672
+ LLVM_DEBUG (llvm::dbgs () << " Found copy inst: " << *user);
673
+ useState.copyInsts .insert ({user, *leafRange});
674
+ }
657
675
}
658
676
return true ;
659
677
}
660
678
}
661
679
662
- // Now that we have handled or loadTakeOrCopy, we need to now track our Takes.
680
+ // Now that we have handled or loadTakeOrCopy, we need to now track our
681
+ // additional pure takes.
663
682
if (::memInstMustConsume (op)) {
664
683
auto leafRange = TypeTreeLeafTypeRange::get (op->get (), getRootAddress ());
665
684
if (!leafRange)
@@ -956,6 +975,65 @@ void BlockSummaries::summarize(SILBasicBlock &block) {
956
975
}
957
976
}
958
977
978
+ {
979
+ auto iter = addressUseState.copyInsts .find (&inst);
980
+ if (iter != addressUseState.copyInsts .end ()) {
981
+ // If we are not yet tracking a "take up" or a "liveness up", then we
982
+ // can update our state. In those other two cases we emit an error
983
+ // diagnostic below.
984
+ if (!state.isTrackingAnyState ()) {
985
+ LLVM_DEBUG (llvm::dbgs ()
986
+ << " Tracking new take up: " << *iter->first );
987
+ state.trackTake (iter->first , iter->second );
988
+ continue ;
989
+ }
990
+
991
+ bool emittedSomeDiagnostic = false ;
992
+ if (auto *takeUp = state.getTakeUp ()) {
993
+ LLVM_DEBUG (llvm::dbgs () << " Found two takes, emitting error!\n " );
994
+ LLVM_DEBUG (llvm::dbgs () << " First take: " << *takeUp);
995
+ LLVM_DEBUG (llvm::dbgs () << " Second take: " << inst);
996
+ diagnosticEmitter.emitAddressDiagnostic (markedAddress, takeUp, &inst,
997
+ true /* is consuming*/ );
998
+ emittedSomeDiagnostic = true ;
999
+ }
1000
+
1001
+ // If we found a liveness inst, we are going to emit an error since we
1002
+ // have a use after free.
1003
+ if (auto *livenessUpInst = state.getLivenessUp ()) {
1004
+ // If we are tracking state for an inout and our liveness inst is a
1005
+ // function exiting instruction, we want to emit a special
1006
+ // diagnostic error saying that the user has not reinitialized inout
1007
+ // along a path to the end of the function.
1008
+ if (livenessUpInst == term && isInOut) {
1009
+ LLVM_DEBUG (llvm::dbgs ()
1010
+ << " Found liveness inout error: " << inst);
1011
+ // Even though we emit a diagnostic for inout here, we actually
1012
+ // want to no longer track the inout liveness use and instead want
1013
+ // to track the consuming use so that earlier errors are on the
1014
+ // take and not on the inout. This is to ensure that we only emit
1015
+ // a single inout not reinitialized before end of function error
1016
+ // if we have multiple consumes along that path.
1017
+ diagnosticEmitter.emitInOutEndOfFunctionDiagnostic (markedAddress,
1018
+ &inst);
1019
+ state.trackTakeForLivenessError (iter->first , iter->second );
1020
+ } else {
1021
+ // Otherwise, we just emit a normal liveness error.
1022
+ LLVM_DEBUG (llvm::dbgs () << " Found liveness error: " << inst);
1023
+ diagnosticEmitter.emitAddressDiagnostic (markedAddress,
1024
+ livenessUpInst, &inst,
1025
+ false /* is not consuming*/ );
1026
+ state.trackTakeForLivenessError (iter->first , iter->second );
1027
+ }
1028
+ emittedSomeDiagnostic = true ;
1029
+ }
1030
+
1031
+ (void )emittedSomeDiagnostic;
1032
+ assert (emittedSomeDiagnostic);
1033
+ continue ;
1034
+ }
1035
+ }
1036
+
959
1037
{
960
1038
auto iter = addressUseState.livenessUses .find (&inst);
961
1039
if (iter != addressUseState.livenessUses .end ()) {
@@ -1424,27 +1502,24 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
1424
1502
addressUseState.reinitInsts .count (&*ii))
1425
1503
break ;
1426
1504
1427
- if (addressUseState.takeInsts .count (&*ii)) {
1505
+ assert (!addressUseState.takeInsts .count (&*ii) &&
1506
+ " Double destroy?! Should have errored on this?!" );
1507
+
1508
+ if (addressUseState.copyInsts .count (&*ii)) {
1428
1509
if (auto *li = dyn_cast<LoadInst>(&*ii)) {
1429
- if (li->getOwnershipQualifier () == LoadOwnershipQualifier::Copy) {
1430
- // If we have a copy in the single block case, erase the destroy
1431
- // and visit the next one.
1432
- destroy->eraseFromParent ();
1433
- changed = true ;
1434
- foundSingleBlockCase = true ;
1435
- break ;
1436
- }
1437
- llvm_unreachable (" Error?! This is a double destroy?!" );
1510
+ // If we have a copy in the single block case, erase the destroy
1511
+ // and visit the next one.
1512
+ destroy->eraseFromParent ();
1513
+ changed = true ;
1514
+ foundSingleBlockCase = true ;
1515
+ break ;
1438
1516
}
1439
1517
1440
1518
if (auto *copyAddr = dyn_cast<CopyAddrInst>(&*ii)) {
1441
- if (!copyAddr->isTakeOfSrc ()) {
1442
- destroy->eraseFromParent ();
1443
- changed = true ;
1444
- foundSingleBlockCase = true ;
1445
- break ;
1446
- }
1447
- llvm_unreachable (" Error?! This is a double destroy?!" );
1519
+ destroy->eraseFromParent ();
1520
+ changed = true ;
1521
+ foundSingleBlockCase = true ;
1522
+ break ;
1448
1523
}
1449
1524
}
1450
1525
@@ -1463,36 +1538,25 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
1463
1538
// Now that we have rewritten all borrows, convert any takes that are today
1464
1539
// copies into their take form. If we couldn't do this, we would have had an
1465
1540
// error.
1466
- for (auto take : addressUseState.takeInsts ) {
1541
+ for (auto take : addressUseState.copyInsts ) {
1467
1542
if (auto *li = dyn_cast<LoadInst>(take.first )) {
1468
- switch (li->getOwnershipQualifier ()) {
1469
- case LoadOwnershipQualifier::Unqualified:
1470
- case LoadOwnershipQualifier::Trivial:
1471
- llvm_unreachable (" Should never hit this" );
1472
- case LoadOwnershipQualifier::Take:
1473
- // This is already correct.
1474
- continue ;
1475
- case LoadOwnershipQualifier::Copy:
1476
- // Convert this to its take form.
1477
- if (auto *access = dyn_cast<BeginAccessInst>(li->getOperand ()))
1478
- access->setAccessKind (SILAccessKind::Modify);
1479
- li->setOwnershipQualifier (LoadOwnershipQualifier::Take);
1480
- changed = true ;
1481
- continue ;
1482
- }
1543
+ // Convert this to its take form.
1544
+ if (auto *access = dyn_cast<BeginAccessInst>(li->getOperand ()))
1545
+ access->setAccessKind (SILAccessKind::Modify);
1546
+ li->setOwnershipQualifier (LoadOwnershipQualifier::Take);
1547
+ changed = true ;
1548
+ continue ;
1483
1549
}
1484
1550
1485
1551
if (auto *copy = dyn_cast<CopyAddrInst>(take.first )) {
1486
- if (copy->isTakeOfSrc ())
1487
- continue ;
1488
1552
// Convert this to its take form.
1489
1553
if (auto *access = dyn_cast<BeginAccessInst>(copy->getSrc ()))
1490
1554
access->setAccessKind (SILAccessKind::Modify);
1491
1555
copy->setIsTakeOfSrc (IsTake);
1492
1556
continue ;
1493
1557
}
1494
1558
1495
- llvm::dbgs () << " Take User : " << *take.first ;
1559
+ llvm::dbgs () << " Unhandled copy user : " << *take.first ;
1496
1560
llvm_unreachable (" Unhandled case?!" );
1497
1561
}
1498
1562
0 commit comments