@@ -292,6 +292,7 @@ struct UseState {
292292 llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > livenessUses;
293293 llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > borrows;
294294 llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > takeInsts;
295+ llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > copyInsts;
295296 llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > initInsts;
296297 llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 > reinitInsts;
297298
@@ -301,6 +302,7 @@ struct UseState {
301302 destroys.clear ();
302303 livenessUses.clear ();
303304 borrows.clear ();
305+ copyInsts.clear ();
304306 takeInsts.clear ();
305307 initInsts.clear ();
306308 reinitInsts.clear ();
@@ -552,6 +554,9 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
552554 // At this point, we have handled all of the non-loadTakeOrCopy/consuming
553555 // uses.
554556 if (auto *copyAddr = dyn_cast<CopyAddrInst>(user)) {
557+ assert (op->getOperandNumber () == CopyAddrInst::Src &&
558+ " Should have dest above in memInstMust{Rei,I}nitialize" );
559+
555560 if (markedValue->getCheckKind () == MarkMustCheckInst::CheckKind::NoCopy) {
556561 LLVM_DEBUG (llvm::dbgs ()
557562 << " Found mark must check [nocopy] error: " << *user);
@@ -564,8 +569,13 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
564569 if (!leafRange)
565570 return false ;
566571
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+ }
569579 return true ;
570580 }
571581
@@ -637,7 +647,7 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
637647 }
638648
639649 // 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.
641651 auto leafRange = TypeTreeLeafTypeRange::get (op->get (), getRootAddress ());
642652 if (!leafRange)
643653 return false ;
@@ -652,14 +662,23 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
652662
653663 useState.borrows .insert ({user, *leafRange});
654664 } 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+ }
657675 }
658676 return true ;
659677 }
660678 }
661679
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.
663682 if (::memInstMustConsume (op)) {
664683 auto leafRange = TypeTreeLeafTypeRange::get (op->get (), getRootAddress ());
665684 if (!leafRange)
@@ -956,6 +975,65 @@ void BlockSummaries::summarize(SILBasicBlock &block) {
956975 }
957976 }
958977
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+
9591037 {
9601038 auto iter = addressUseState.livenessUses .find (&inst);
9611039 if (iter != addressUseState.livenessUses .end ()) {
@@ -1424,27 +1502,24 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
14241502 addressUseState.reinitInsts .count (&*ii))
14251503 break ;
14261504
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)) {
14281509 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 ;
14381516 }
14391517
14401518 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 ;
14481523 }
14491524 }
14501525
@@ -1463,36 +1538,25 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
14631538 // Now that we have rewritten all borrows, convert any takes that are today
14641539 // copies into their take form. If we couldn't do this, we would have had an
14651540 // error.
1466- for (auto take : addressUseState.takeInsts ) {
1541+ for (auto take : addressUseState.copyInsts ) {
14671542 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 ;
14831549 }
14841550
14851551 if (auto *copy = dyn_cast<CopyAddrInst>(take.first )) {
1486- if (copy->isTakeOfSrc ())
1487- continue ;
14881552 // Convert this to its take form.
14891553 if (auto *access = dyn_cast<BeginAccessInst>(copy->getSrc ()))
14901554 access->setAccessKind (SILAccessKind::Modify);
14911555 copy->setIsTakeOfSrc (IsTake);
14921556 continue ;
14931557 }
14941558
1495- llvm::dbgs () << " Take User : " << *take.first ;
1559+ llvm::dbgs () << " Unhandled copy user : " << *take.first ;
14961560 llvm_unreachable (" Unhandled case?!" );
14971561 }
14981562
0 commit comments