@@ -1452,10 +1452,12 @@ struct CopiedLoadBorrowEliminationVisitor final
1452
1452
// MARK: DestructureThroughDeinit Checking
1453
1453
// ===----------------------------------------------------------------------===//
1454
1454
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) {
1459
1461
LLVM_DEBUG (llvm::dbgs () << " DestructureNeedingUse: " << *use->getUser ());
1460
1462
1461
1463
SILFunction *fn = rootAddress->getFunction ();
@@ -1473,6 +1475,29 @@ checkForDestructureThroughDeinit(MarkMustCheckInst *rootAddress, Operand *use,
1473
1475
if (iterType.isMoveOnlyWrapped ())
1474
1476
return ;
1475
1477
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.
1476
1501
while (iterType != targetType) {
1477
1502
// If we have a nominal type as our parent type, see if it has a
1478
1503
// deinit. We know that it must be non-copyable since copyable types
@@ -1491,8 +1516,9 @@ checkForDestructureThroughDeinit(MarkMustCheckInst *rootAddress, Operand *use,
1491
1516
pair.constructPathString (iterType, {rootType, fn}, rootType, fn, os);
1492
1517
}
1493
1518
1494
- diagnosticEmitter.emitCannotDestructureDeinitNominalError (
1495
- rootAddress, pathString, nom, use->getUser ());
1519
+ diagnosticEmitter.emitCannotDestructureNominalError (
1520
+ rootAddress, pathString, nom, use->getUser (),
1521
+ true /* is for deinit error*/ );
1496
1522
break ;
1497
1523
}
1498
1524
}
@@ -1702,8 +1728,10 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1702
1728
1703
1729
// TODO: Add borrow checking here like below.
1704
1730
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);
1707
1735
1708
1736
if (copyAddr->isTakeOfSrc ()) {
1709
1737
LLVM_DEBUG (llvm::dbgs () << " Found take: " << *user);
@@ -1771,17 +1799,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1771
1799
return false ;
1772
1800
}
1773
1801
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
-
1785
1802
// Canonicalize the lifetime of the load [take], load [copy].
1786
1803
LLVM_DEBUG (llvm::dbgs () << " Running copy propagation!\n " );
1787
1804
moveChecker.changed |= moveChecker.canonicalizer .canonicalize ();
@@ -1882,6 +1899,19 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1882
1899
useState.recordLivenessUse (dvi, *leafRange);
1883
1900
}
1884
1901
} 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
+
1885
1915
// If we had a load [copy], store this into the copy list. These are the
1886
1916
// things that we must merge into destroy_addr or reinits after we are
1887
1917
// done checking. The load [take] are already complete and good to go.
@@ -1926,8 +1956,7 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1926
1956
// error.
1927
1957
unsigned numDiagnostics =
1928
1958
moveChecker.diagnosticEmitter .getDiagnosticCount ();
1929
- checkForDestructureThroughDeinit (markedValue, op, *leafRange,
1930
- diagnosticEmitter);
1959
+ checkForDestructure (markedValue, op, *leafRange, diagnosticEmitter);
1931
1960
if (numDiagnostics != moveChecker.diagnosticEmitter .getDiagnosticCount ()) {
1932
1961
LLVM_DEBUG (llvm::dbgs ()
1933
1962
<< " Emitting destructure through deinit error!\n " );
0 commit comments