@@ -443,8 +443,15 @@ class LetValueInitialization : public Initialization {
443
443
444
444
public:
445
445
LetValueInitialization (VarDecl *vd, SILGenFunction &SGF) : vd(vd) {
446
- auto &lowering = SGF.getTypeLowering (vd->getType ());
447
-
446
+ const TypeLowering *lowering = nullptr ;
447
+ if (SGF.getASTContext ().LangOpts .Features .count (Feature::MoveOnly) &&
448
+ vd->getAttrs ().hasAttribute <NoImplicitCopyAttr>()) {
449
+ lowering = &SGF.getTypeLowering (
450
+ SILMoveOnlyType::get (vd->getType ()->getCanonicalType ()));
451
+ } else {
452
+ lowering = &SGF.getTypeLowering (vd->getType ());
453
+ }
454
+
448
455
// Decide whether we need a temporary stack buffer to evaluate this 'let'.
449
456
// There are four cases we need to handle here: parameters, initialized (or
450
457
// bound) decls, uninitialized ones, and async let declarations.
@@ -469,13 +476,13 @@ class LetValueInitialization : public Initialization {
469
476
// If this is a let with an initializer or bound value, we only need a
470
477
// buffer if the type is address only.
471
478
needsTemporaryBuffer =
472
- lowering. isAddressOnly () && SGF.silConv .useLoweredAddresses ();
479
+ lowering-> isAddressOnly () && SGF.silConv .useLoweredAddresses ();
473
480
}
474
481
475
482
// Make sure that we have a non-address only type when binding a
476
483
// @_noImplicitCopy let.
477
- if (SGF.getASTContext ().LangOpts .hasFeature (Feature::MoveOnly) &&
478
- lowering. isAddressOnly () &&
484
+ if (SGF.getASTContext ().LangOpts .Features . count (Feature::MoveOnly) &&
485
+ lowering-> isAddressOnly () &&
479
486
vd->getAttrs ().hasAttribute <NoImplicitCopyAttr>()) {
480
487
auto d = diag::noimplicitcopy_used_on_generic_or_existential;
481
488
diagnose (SGF.getASTContext (), vd->getLoc (), d);
@@ -485,13 +492,13 @@ class LetValueInitialization : public Initialization {
485
492
bool isLexical =
486
493
SGF.getASTContext ().SILOpts .supportsLexicalLifetimes (SGF.getModule ());
487
494
address =
488
- SGF.emitTemporaryAllocation (vd, lowering. getLoweredType (),
495
+ SGF.emitTemporaryAllocation (vd, lowering-> getLoweredType (),
489
496
false /* hasDynamicLifetime*/ , isLexical);
490
497
if (isUninitialized)
491
498
address = SGF.B .createMarkUninitializedVar (vd, address);
492
- DestroyCleanup = SGF.enterDormantTemporaryCleanup (address, lowering);
499
+ DestroyCleanup = SGF.enterDormantTemporaryCleanup (address, * lowering);
493
500
SGF.VarLocs [vd] = SILGenFunction::VarLoc::get (address);
494
- } else if (!lowering. isTrivial ()) {
501
+ } else if (!lowering-> isTrivial ()) {
495
502
// Push a cleanup to destroy the let declaration. This has to be
496
503
// inactive until the variable is initialized: if control flow exits the
497
504
// before the value is bound, we don't want to destroy the value.
@@ -554,31 +561,68 @@ class LetValueInitialization : public Initialization {
554
561
address = value;
555
562
SILLocation PrologueLoc (vd);
556
563
557
- if (SGF.getASTContext ().SILOpts .supportsLexicalLifetimes (SGF.getModule ()) &&
558
- value->getOwnershipKind () != OwnershipKind::None) {
559
- if (!SGF.getASTContext ().LangOpts .hasFeature (Feature::MoveOnly)) {
560
- value = SILValue (
561
- SGF.B .createBeginBorrow (PrologueLoc, value, /* isLexical*/ true ));
562
- } else {
563
- // If we have an owned value that had a cleanup, then create a
564
- // move_value that acts as a consuming use of the value. The reason why
565
- // we want this is even if we are only performing a borrow for our
566
- // lexical lifetime, we want to ensure that our defs see this
567
- // initialization as consuming this value.
568
- if (value->getOwnershipKind () == OwnershipKind::Owned) {
569
- assert (wasPlusOne);
570
- value = SILValue (SGF.B .createMoveValue (PrologueLoc, value));
571
- }
564
+ if (SGF.getASTContext ().SILOpts .supportsLexicalLifetimes (SGF.getModule ())) {
565
+ if (value->getOwnershipKind () != OwnershipKind::None) {
566
+ if (!SGF.getASTContext ().LangOpts .Features .count (Feature::MoveOnly)) {
567
+ value =
568
+ SGF.B .createBeginBorrow (PrologueLoc, value, /* isLexical*/ true );
569
+ } else {
570
+ // If we have an owned moveonly value that had a cleanup, then create
571
+ // a move_value that acts as a consuming use of the value. The reason
572
+ // why we want this is even if we are only performing a borrow for our
573
+ // lexical lifetime, we want to ensure that our defs see this
574
+ // initialization as consuming this value.
575
+ if (value->getType ().isMoveOnlyWrapped () &&
576
+ value->getOwnershipKind () == OwnershipKind::Owned) {
577
+ assert (wasPlusOne);
578
+ // NOTE: If our type is trivial when not wrapped in a
579
+ // SILMoveOnlyType, this will return a trivial value. We rely on the
580
+ // checker to determine if this is an acceptable use of the value.
581
+ value = SGF.B .createOwnedMoveOnlyWrapperToCopyableValue (PrologueLoc,
582
+ value);
583
+ }
572
584
573
- if (vd->getAttrs ().hasAttribute <NoImplicitCopyAttr>()) {
574
- value = SILValue (SGF.B .createBeginBorrow (PrologueLoc, value,
575
- /* isLexical*/ true ));
576
- value = SGF.B .createCopyValue (PrologueLoc, value);
585
+ // If we still have a non-trivial thing, emit code that will need to
586
+ // be cleaned up. If we are now trivial, we do not need to cleanup
587
+ // anything.
588
+ if (!value->getType ().isTrivial (SGF.F )) {
589
+ if (vd->getAttrs ().hasAttribute <NoImplicitCopyAttr>()) {
590
+ value = SGF.B .createBeginBorrow (PrologueLoc, value,
591
+ /* isLexical*/ true );
592
+ value = SGF.B .createCopyValue (PrologueLoc, value);
593
+ value = SGF.B .createCopyableToMoveOnlyWrapperValue (PrologueLoc,
594
+ value);
595
+ value = SGF.B .createMarkMustCheckInst (
596
+ PrologueLoc, value,
597
+ MarkMustCheckInst::CheckKind::NoImplicitCopy);
598
+ } else {
599
+ value = SGF.B .createBeginBorrow (PrologueLoc, value,
600
+ /* isLexical*/ true );
601
+ }
602
+ }
603
+ }
604
+ } else {
605
+ if (SGF.getASTContext ().LangOpts .Features .count (Feature::MoveOnly) &&
606
+ vd->getAttrs ().hasAttribute <NoImplicitCopyAttr>() &&
607
+ value->getType ().isTrivial (SGF.F )) {
608
+ // We are abusing this. This should be a separate instruction just for
609
+ // converting from copyable trivial to move only. I am abusing it
610
+ // here by using it multiple times in different ways.
611
+ value =
612
+ SGF.B .createCopyableToMoveOnlyWrapperValue (PrologueLoc, value);
613
+ value = SGF.B .createBeginBorrow (PrologueLoc, value,
614
+ /* isLexical*/ true );
615
+ // We use an explicit copy value since:
616
+ //
617
+ // 1. We already have a move only type here. So we can't use a normal
618
+ // copy here due to the pattern we are creating. We could avoid this,
619
+ // but it is not worth fixing b/c of point 2.
620
+ //
621
+ // 2. Since this is a trivial value, when we remove their move only
622
+ // ness, this will become a no-op meaning no-overhead.
623
+ value = SGF.B .createExplicitCopyValue (PrologueLoc, value);
577
624
value = SGF.B .createMarkMustCheckInst (
578
625
PrologueLoc, value, MarkMustCheckInst::CheckKind::NoImplicitCopy);
579
- } else {
580
- value = SILValue (
581
- SGF.B .createBeginBorrow (PrologueLoc, value, /* isLexical*/ true ));
582
626
}
583
627
}
584
628
}
@@ -608,7 +652,8 @@ class LetValueInitialization : public Initialization {
608
652
// Disable the rvalue expression cleanup, since the let value
609
653
// initialization has a cleanup that lives for the entire scope of the
610
654
// let declaration.
611
- bindValue (value.forward (SGF), SGF, value.isPlusOne (SGF));
655
+ bool isPlusOne = value.isPlusOne (SGF);
656
+ bindValue (value.forward (SGF), SGF, isPlusOne);
612
657
} else {
613
658
// Disable the expression cleanup of the copy, since the let value
614
659
// initialization has a cleanup that lives for the entire scope of the
@@ -631,8 +676,9 @@ class LetValueInitialization : public Initialization {
631
676
SGF.Cleanups .forwardCleanup (cleanup);
632
677
633
678
// Activate the destroy cleanup.
634
- if (DestroyCleanup != CleanupHandle::invalid ())
679
+ if (DestroyCleanup != CleanupHandle::invalid ()) {
635
680
SGF.Cleanups .setCleanupState (DestroyCleanup, CleanupState::Active);
681
+ }
636
682
637
683
DidFinish = true ;
638
684
}
@@ -1795,6 +1841,9 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
1795
1841
return ;
1796
1842
}
1797
1843
1844
+ // This handles any case where we copy + begin_borrow or copyable_to_moveonly
1845
+ // + begin_borrow. In either case we just need to end the lifetime of the
1846
+ // begin_borrow's operand.
1798
1847
if (auto *bbi = dyn_cast<BeginBorrowInst>(Val.getDefiningInstruction ())) {
1799
1848
B.createEndBorrow (silLoc, bbi);
1800
1849
B.emitDestroyValueOperation (silLoc, bbi->getOperand ());
@@ -1814,6 +1863,31 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
1814
1863
}
1815
1864
}
1816
1865
}
1866
+
1867
+ if (auto *copyToMove = dyn_cast<CopyableToMoveOnlyWrapperValueInst>(
1868
+ mvi->getOperand ())) {
1869
+ if (auto *cvi = dyn_cast<CopyValueInst>(copyToMove->getOperand ())) {
1870
+ if (auto *bbi = dyn_cast<BeginBorrowInst>(cvi->getOperand ())) {
1871
+ if (bbi->isLexical ()) {
1872
+ B.emitDestroyValueOperation (silLoc, mvi);
1873
+ B.createEndBorrow (silLoc, bbi);
1874
+ B.emitDestroyValueOperation (silLoc, bbi->getOperand ());
1875
+ return ;
1876
+ }
1877
+ }
1878
+ }
1879
+ }
1880
+
1881
+ if (auto *cvi = dyn_cast<ExplicitCopyValueInst>(mvi->getOperand ())) {
1882
+ if (auto *bbi = dyn_cast<BeginBorrowInst>(cvi->getOperand ())) {
1883
+ if (bbi->isLexical ()) {
1884
+ B.emitDestroyValueOperation (silLoc, mvi);
1885
+ B.createEndBorrow (silLoc, bbi);
1886
+ B.emitDestroyValueOperation (silLoc, bbi->getOperand ());
1887
+ return ;
1888
+ }
1889
+ }
1890
+ }
1817
1891
}
1818
1892
}
1819
1893
}
0 commit comments