@@ -1452,10 +1452,12 @@ struct CopiedLoadBorrowEliminationVisitor final
14521452// MARK: DestructureThroughDeinit Checking
14531453// ===----------------------------------------------------------------------===//
14541454
1455- static void
1456- checkForDestructureThroughDeinit (MarkMustCheckInst *rootAddress, Operand *use,
1457- TypeTreeLeafTypeRange usedBits,
1458- DiagnosticEmitter &diagnosticEmitter) {
1455+ // / When partial consumption is enabled, we only allow for destructure through
1456+ // / deinits. When partial consumption is disabled, we error on /all/ partial
1457+ // / consumption.
1458+ static void checkForDestructure (MarkMustCheckInst *rootAddress, Operand *use,
1459+ TypeTreeLeafTypeRange usedBits,
1460+ DiagnosticEmitter &diagnosticEmitter) {
14591461 LLVM_DEBUG (llvm::dbgs () << " DestructureNeedingUse: " << *use->getUser ());
14601462
14611463 SILFunction *fn = rootAddress->getFunction ();
@@ -1473,6 +1475,29 @@ checkForDestructureThroughDeinit(MarkMustCheckInst *rootAddress, Operand *use,
14731475 if (iterType.isMoveOnlyWrapped ())
14741476 return ;
14751477
1478+ // If we are not allowing for any partial consumption, just emit an error
1479+ // immediately.
1480+ if (!rootAddress->getModule ().getASTContext ().LangOpts .hasFeature (
1481+ Feature::MoveOnlyPartialConsumption)) {
1482+ // If the types equal, just bail early.
1483+ if (iterType == targetType)
1484+ return ;
1485+
1486+ // Otherwise, build up the path string and emit the error.
1487+ SmallString<128 > pathString;
1488+ auto rootType = rootAddress->getType ();
1489+ if (iterType != rootType) {
1490+ llvm::raw_svector_ostream os (pathString);
1491+ pair.constructPathString (iterType, {rootType, fn}, rootType, fn, os);
1492+ }
1493+
1494+ diagnosticEmitter.emitCannotDestructureNominalError (
1495+ rootAddress, pathString, nullptr /* nominal*/ , use->getUser (),
1496+ false /* is for deinit error*/ );
1497+ return ;
1498+ }
1499+
1500+ // Otherwise, walk the type looking for the deinit.
14761501 while (iterType != targetType) {
14771502 // If we have a nominal type as our parent type, see if it has a
14781503 // deinit. We know that it must be non-copyable since copyable types
@@ -1491,8 +1516,9 @@ checkForDestructureThroughDeinit(MarkMustCheckInst *rootAddress, Operand *use,
14911516 pair.constructPathString (iterType, {rootType, fn}, rootType, fn, os);
14921517 }
14931518
1494- diagnosticEmitter.emitCannotDestructureDeinitNominalError (
1495- rootAddress, pathString, nom, use->getUser ());
1519+ diagnosticEmitter.emitCannotDestructureNominalError (
1520+ rootAddress, pathString, nom, use->getUser (),
1521+ true /* is for deinit error*/ );
14961522 break ;
14971523 }
14981524 }
@@ -1702,8 +1728,10 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
17021728
17031729 // TODO: Add borrow checking here like below.
17041730
1705- // TODO: Add destructure deinit checking here once address only checking is
1706- // completely brought up.
1731+ // If we have a copy_addr, we are either going to have a take or a
1732+ // copy... in either case, this copy_addr /is/ going to be a consuming
1733+ // operation. Make sure to check if we semantically destructure.
1734+ checkForDestructure (markedValue, op, *leafRange, diagnosticEmitter);
17071735
17081736 if (copyAddr->isTakeOfSrc ()) {
17091737 LLVM_DEBUG (llvm::dbgs () << " Found take: " << *user);
@@ -1771,17 +1799,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
17711799 return false ;
17721800 }
17731801
1774- checkForDestructureThroughDeinit (markedValue, op, *leafRange,
1775- diagnosticEmitter);
1776-
1777- // If we emitted an error diagnostic, do not transform further and instead
1778- // mark that we emitted an early diagnostic and return true.
1779- if (numDiagnostics != moveChecker.diagnosticEmitter .getDiagnosticCount ()) {
1780- LLVM_DEBUG (llvm::dbgs ()
1781- << " Emitting destructure through deinit error!\n " );
1782- return true ;
1783- }
1784-
17851802 // Canonicalize the lifetime of the load [take], load [copy].
17861803 LLVM_DEBUG (llvm::dbgs () << " Running copy propagation!\n " );
17871804 moveChecker.changed |= moveChecker.canonicalizer .canonicalize ();
@@ -1882,6 +1899,19 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
18821899 useState.recordLivenessUse (dvi, *leafRange);
18831900 }
18841901 } else {
1902+ // Now that we know that we are going to perform a take, perform a
1903+ // checkForDestructure.
1904+ checkForDestructure (markedValue, op, *leafRange, diagnosticEmitter);
1905+
1906+ // If we emitted an error diagnostic, do not transform further and instead
1907+ // mark that we emitted an early diagnostic and return true.
1908+ if (numDiagnostics !=
1909+ moveChecker.diagnosticEmitter .getDiagnosticCount ()) {
1910+ LLVM_DEBUG (llvm::dbgs ()
1911+ << " Emitting destructure through deinit error!\n " );
1912+ return true ;
1913+ }
1914+
18851915 // If we had a load [copy], store this into the copy list. These are the
18861916 // things that we must merge into destroy_addr or reinits after we are
18871917 // done checking. The load [take] are already complete and good to go.
@@ -1926,8 +1956,7 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
19261956 // error.
19271957 unsigned numDiagnostics =
19281958 moveChecker.diagnosticEmitter .getDiagnosticCount ();
1929- checkForDestructureThroughDeinit (markedValue, op, *leafRange,
1930- diagnosticEmitter);
1959+ checkForDestructure (markedValue, op, *leafRange, diagnosticEmitter);
19311960 if (numDiagnostics != moveChecker.diagnosticEmitter .getDiagnosticCount ()) {
19321961 LLVM_DEBUG (llvm::dbgs ()
19331962 << " Emitting destructure through deinit error!\n " );
0 commit comments