225
225
#include " swift/AST/AccessScope.h"
226
226
#include " swift/AST/DiagnosticEngine.h"
227
227
#include " swift/AST/DiagnosticsSIL.h"
228
+ #include " swift/AST/SemanticAttrs.h"
228
229
#include " swift/Basic/Debug.h"
229
230
#include " swift/Basic/Defer.h"
230
231
#include " swift/Basic/FrozenMultiMap.h"
@@ -433,7 +434,7 @@ static bool memInstMustConsume(Operand *memOper) {
433
434
return false ;
434
435
ApplySite applySite (pai);
435
436
auto convention = applySite.getArgumentConvention (*memOper);
436
- return convention.isInoutConvention ();
437
+ return ! convention.isInoutConvention ();
437
438
}
438
439
case SILInstructionKind::DestroyAddrInst:
439
440
return true ;
@@ -492,6 +493,92 @@ static bool isInOutDefThatNeedsEndOfFunctionLiveness(MarkMustCheckInst *markedAd
492
493
return false ;
493
494
}
494
495
496
+ // ===----------------------------------------------------------------------===//
497
+ // MARK: Partial Apply Utilities
498
+ // ===----------------------------------------------------------------------===//
499
+
500
+ static bool findNonEscapingPartialApplyUses (
501
+ PartialApplyInst *pai, TypeTreeLeafTypeRange leafRange,
502
+ llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4 >
503
+ &livenessUses) {
504
+ StackList<Operand *> worklist (pai->getFunction ());
505
+ for (auto *use : pai->getUses ())
506
+ worklist.push_back (use);
507
+
508
+ LLVM_DEBUG (llvm::dbgs () << " Searching for partial apply uses!\n " );
509
+ while (!worklist.empty ()) {
510
+ auto *use = worklist.pop_back_val ();
511
+
512
+ if (use->isTypeDependent ())
513
+ continue ;
514
+
515
+ auto *user = use->getUser ();
516
+
517
+ // These instructions do not cause us to escape.
518
+ if (isIncidentalUse (user) || isa<DestroyValueInst>(user))
519
+ continue ;
520
+
521
+ // Look through these instructions.
522
+ if (isa<BeginBorrowInst>(user) || isa<CopyValueInst>(user) ||
523
+ isa<MoveValueInst>(user) ||
524
+ // If we capture this partial_apply in another partial_apply, then we
525
+ // know that said partial_apply must not have escaped the value since
526
+ // otherwise we could not have an inout_aliasable argument or be
527
+ // on_stack. Process it recursively so that we treat uses of that
528
+ // partial_apply and applies of that partial_apply as uses of our
529
+ // partial_apply.
530
+ //
531
+ // We have this separately from the other look through sections so that
532
+ // we can make it clearer what we are doing here.
533
+ isa<PartialApplyInst>(user)) {
534
+ for (auto *use : cast<SingleValueInstruction>(user)->getUses ())
535
+ worklist.push_back (use);
536
+ continue ;
537
+ }
538
+
539
+ // If we have a mark_dependence and are the value, look through the
540
+ // mark_dependence.
541
+ if (auto *mdi = dyn_cast<MarkDependenceInst>(user)) {
542
+ if (mdi->getValue () == use->get ()) {
543
+ for (auto *use : mdi->getUses ())
544
+ worklist.push_back (use);
545
+ continue ;
546
+ }
547
+ }
548
+
549
+ if (auto apply = FullApplySite::isa (user)) {
550
+ // If we apply the function or pass the function off to an apply, then we
551
+ // need to treat the function application as a liveness use of the
552
+ // variable since if the partial_apply is invoked within the function
553
+ // application, we may access the captured variable.
554
+ livenessUses.insert ({user, leafRange});
555
+ if (apply.beginsCoroutineEvaluation ()) {
556
+ // If we have a coroutine, we need to treat the abort_apply and
557
+ // end_apply as liveness uses since once we execute one of those
558
+ // instructions, we have returned control to the coroutine which means
559
+ // that we could then access the captured variable again.
560
+ auto *bai = cast<BeginApplyInst>(user);
561
+ SmallVector<EndApplyInst *, 4 > endApplies;
562
+ SmallVector<AbortApplyInst *, 4 > abortApplies;
563
+ bai->getCoroutineEndPoints (endApplies, abortApplies);
564
+ for (auto *eai : endApplies)
565
+ livenessUses.insert ({eai, leafRange});
566
+ for (auto *aai : abortApplies)
567
+ livenessUses.insert ({aai, leafRange});
568
+ }
569
+ continue ;
570
+ }
571
+
572
+ LLVM_DEBUG (
573
+ llvm::dbgs ()
574
+ << " Found instruction we did not understand... returning false!\n " );
575
+ LLVM_DEBUG (llvm::dbgs () << " Instruction: " << *user);
576
+ return false ;
577
+ }
578
+
579
+ return true ;
580
+ }
581
+
495
582
// ===----------------------------------------------------------------------===//
496
583
// MARK: Find Candidate Mark Must Checks
497
584
// ===----------------------------------------------------------------------===//
@@ -1354,7 +1441,6 @@ struct GatherUsesVisitor final : public TransitiveAddressWalker {
1354
1441
MoveOnlyAddressCheckerPImpl &moveChecker;
1355
1442
UseState &useState;
1356
1443
MarkMustCheckInst *markedValue;
1357
- bool emittedEarlyDiagnostic = false ;
1358
1444
DiagnosticEmitter &diagnosticEmitter;
1359
1445
1360
1446
// Pruned liveness used to validate that load [take]/load [copy] can be
@@ -1529,14 +1615,13 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1529
1615
if (isa<ProjectBoxInst>(stripAccessMarkers (markedValue->getOperand ()))) {
1530
1616
LLVM_DEBUG (llvm::dbgs ()
1531
1617
<< " Found mark must check [nocopy] use of escaping box: " << *user);
1532
- diagnosticEmitter.emitAddressEscapingClosureCaptureLoadedAndConsumed (markedValue);
1533
- emittedEarlyDiagnostic = true ;
1618
+ diagnosticEmitter.emitAddressEscapingClosureCaptureLoadedAndConsumed (
1619
+ markedValue) ;
1534
1620
return true ;
1535
1621
}
1536
1622
LLVM_DEBUG (llvm::dbgs ()
1537
1623
<< " Found mark must check [nocopy] error: " << *user);
1538
1624
diagnosticEmitter.emitAddressDiagnosticNoCopy (markedValue, copyAddr);
1539
- emittedEarlyDiagnostic = true ;
1540
1625
return true ;
1541
1626
}
1542
1627
@@ -1592,15 +1677,13 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1592
1677
.didEmitCheckerDoesntUnderstandDiagnostic ());
1593
1678
LLVM_DEBUG (llvm::dbgs ()
1594
1679
<< " Failed to perform borrow to destructure transform!\n " );
1595
- emittedEarlyDiagnostic = true ;
1596
1680
return false ;
1597
1681
}
1598
1682
1599
1683
// If we emitted an error diagnostic, do not transform further and instead
1600
1684
// mark that we emitted an early diagnostic and return true.
1601
1685
if (numDiagnostics != moveChecker.diagnosticEmitter .getDiagnosticCount ()) {
1602
1686
LLVM_DEBUG (llvm::dbgs () << " Emitting borrow to destructure error!\n " );
1603
- emittedEarlyDiagnostic = true ;
1604
1687
return true ;
1605
1688
}
1606
1689
@@ -1621,7 +1704,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1621
1704
if (numDiagnostics != moveChecker.diagnosticEmitter .getDiagnosticCount ()) {
1622
1705
LLVM_DEBUG (llvm::dbgs ()
1623
1706
<< " Emitting destructure through deinit error!\n " );
1624
- emittedEarlyDiagnostic = true ;
1625
1707
return true ;
1626
1708
}
1627
1709
@@ -1639,14 +1721,18 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1639
1721
<< " Found mark must check [nocopy] error: " << *user);
1640
1722
auto *fArg = dyn_cast<SILFunctionArgument>(
1641
1723
stripAccessMarkers (markedValue->getOperand ()));
1642
- if (fArg && fArg ->isClosureCapture () && fArg ->getType ().isAddress ()) {
1643
- moveChecker.diagnosticEmitter .emitPromotedBoxArgumentError (
1644
- markedValue, fArg );
1724
+ // If we have a closure captured that we specialized, we should have a
1725
+ // no consume or assign and should emit a normal guaranteed diagnostic.
1726
+ if (fArg && fArg ->isClosureCapture () &&
1727
+ fArg ->getArgumentConvention ().isInoutConvention ()) {
1728
+ assert (checkKind == MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
1729
+ moveChecker.diagnosticEmitter .emitObjectGuaranteedDiagnostic (
1730
+ markedValue);
1645
1731
} else {
1732
+ // Otherwise, we need to emit an escaping closure error.
1646
1733
moveChecker.diagnosticEmitter
1647
1734
.emitAddressEscapingClosureCaptureLoadedAndConsumed (markedValue);
1648
1735
}
1649
- emittedEarlyDiagnostic = true ;
1650
1736
return true ;
1651
1737
}
1652
1738
@@ -1660,7 +1746,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1660
1746
1661
1747
if (checkForExclusivityHazards (li)) {
1662
1748
LLVM_DEBUG (llvm::dbgs () << " Found exclusivity violation?!\n " );
1663
- emittedEarlyDiagnostic = true ;
1664
1749
return true ;
1665
1750
}
1666
1751
@@ -1693,7 +1778,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1693
1778
// succeeded.
1694
1779
// Otherwise, emit the diagnostic.
1695
1780
moveChecker.diagnosticEmitter .emitObjectOwnedDiagnostic (markedValue);
1696
- emittedEarlyDiagnostic = true ;
1697
1781
LLVM_DEBUG (llvm::dbgs () << " Emitted early object level diagnostic.\n " );
1698
1782
return true ;
1699
1783
}
@@ -1702,7 +1786,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1702
1786
LLVM_DEBUG (llvm::dbgs () << " Found potential borrow inst: " << *user);
1703
1787
if (checkForExclusivityHazards (li)) {
1704
1788
LLVM_DEBUG (llvm::dbgs () << " Found exclusivity violation?!\n " );
1705
- emittedEarlyDiagnostic = true ;
1706
1789
return true ;
1707
1790
}
1708
1791
@@ -1751,7 +1834,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1751
1834
moveChecker.diagnosticEmitter
1752
1835
.emitAddressEscapingClosureCaptureLoadedAndConsumed (markedValue);
1753
1836
}
1754
- emittedEarlyDiagnostic = true ;
1755
1837
return true ;
1756
1838
}
1757
1839
@@ -1802,8 +1884,22 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1802
1884
}
1803
1885
1804
1886
if (auto *pas = dyn_cast<PartialApplyInst>(user)) {
1805
- if (pas->isOnStack ()) {
1806
- LLVM_DEBUG (llvm::dbgs () << " Found on stack partial apply!\n " );
1887
+ if (auto *fArg = dyn_cast<SILFunctionArgument>(
1888
+ stripAccessMarkers (markedValue->getOperand ()))) {
1889
+ // If we are processing an inout convention and we emitted an error on the
1890
+ // partial_apply, we shouldn't process this mark_must_check, but squelch
1891
+ // the compiler doesn't understand error.
1892
+ if (fArg ->getArgumentConvention ().isInoutConvention () &&
1893
+ pas->getCalleeFunction ()->hasSemanticsAttr (
1894
+ semantics::NO_MOVEONLY_DIAGNOSTICS)) {
1895
+ diagnosticEmitter.emitEarlierPassEmittedDiagnostic (markedValue);
1896
+ return false ;
1897
+ }
1898
+ }
1899
+
1900
+ if (pas->isOnStack () ||
1901
+ ApplySite (pas).getArgumentConvention (*op).isInoutConvention ()) {
1902
+ LLVM_DEBUG (llvm::dbgs () << " Found on stack partial apply or inout usage!\n " );
1807
1903
// On-stack partial applications and their final consumes are always a
1808
1904
// liveness use of their captures.
1809
1905
auto leafRange = TypeTreeLeafTypeRange::get (op->get (), getRootAddress ());
@@ -1812,13 +1908,18 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1812
1908
return false ;
1813
1909
}
1814
1910
1815
- useState.livenessUses .insert ({user, *leafRange});
1816
- for (auto *use : pas->getConsumingUses ()) {
1817
- LLVM_DEBUG (llvm::dbgs ()
1818
- << " Adding consuming use of partial apply as liveness use: "
1819
- << *use->getUser ());
1820
- useState.livenessUses .insert ({use->getUser (), *leafRange});
1911
+ // Attempt to find calls of the non-escaping partial apply and places
1912
+ // where the partial apply is passed to a function. We treat those as
1913
+ // liveness uses. If we find a use we don't understand, we return false
1914
+ // here.
1915
+ if (!findNonEscapingPartialApplyUses (pas, *leafRange,
1916
+ useState.livenessUses )) {
1917
+ LLVM_DEBUG (
1918
+ llvm::dbgs ()
1919
+ << " Failed to understand use of a non-escaping partial apply?!\n " );
1920
+ return false ;
1821
1921
}
1922
+
1822
1923
return true ;
1823
1924
}
1824
1925
}
@@ -2543,9 +2644,19 @@ bool MoveOnlyAddressChecker::check(
2543
2644
LLVM_DEBUG (llvm::dbgs () << " Visiting: " << *markedValue);
2544
2645
2545
2646
// Perform our address check.
2647
+ unsigned diagnosticEmittedByEarlierPassCount =
2648
+ diagnosticEmitter.getDiagnosticEmittedByEarlierPassCount ();
2546
2649
if (!pimpl.performSingleCheck (markedValue)) {
2547
- LLVM_DEBUG (llvm::dbgs ()
2548
- << " Failed to perform single check! Emitting error!\n " );
2650
+ if (diagnosticEmittedByEarlierPassCount !=
2651
+ diagnosticEmitter.getDiagnosticEmittedByEarlierPassCount ()) {
2652
+ LLVM_DEBUG (
2653
+ llvm::dbgs ()
2654
+ << " Failed to perform single check but found earlier emitted "
2655
+ " error. Not emitting checker doesn't understand diagnostic!\n " );
2656
+ continue ;
2657
+ }
2658
+ LLVM_DEBUG (llvm::dbgs () << " Failed to perform single check! Emitting "
2659
+ " compiler doesn't understand diagnostic!\n " );
2549
2660
// If we fail the address check in some way, set the diagnose!
2550
2661
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic (markedValue);
2551
2662
}
0 commit comments