@@ -443,8 +443,15 @@ class LetValueInitialization : public Initialization {
443443
444444public:
445445 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+
448455 // Decide whether we need a temporary stack buffer to evaluate this 'let'.
449456 // There are four cases we need to handle here: parameters, initialized (or
450457 // bound) decls, uninitialized ones, and async let declarations.
@@ -469,13 +476,13 @@ class LetValueInitialization : public Initialization {
469476 // If this is a let with an initializer or bound value, we only need a
470477 // buffer if the type is address only.
471478 needsTemporaryBuffer =
472- lowering. isAddressOnly () && SGF.silConv .useLoweredAddresses ();
479+ lowering-> isAddressOnly () && SGF.silConv .useLoweredAddresses ();
473480 }
474481
475482 // Make sure that we have a non-address only type when binding a
476483 // @_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 () &&
479486 vd->getAttrs ().hasAttribute <NoImplicitCopyAttr>()) {
480487 auto d = diag::noimplicitcopy_used_on_generic_or_existential;
481488 diagnose (SGF.getASTContext (), vd->getLoc (), d);
@@ -485,13 +492,13 @@ class LetValueInitialization : public Initialization {
485492 bool isLexical =
486493 SGF.getASTContext ().SILOpts .supportsLexicalLifetimes (SGF.getModule ());
487494 address =
488- SGF.emitTemporaryAllocation (vd, lowering. getLoweredType (),
495+ SGF.emitTemporaryAllocation (vd, lowering-> getLoweredType (),
489496 false /* hasDynamicLifetime*/ , isLexical);
490497 if (isUninitialized)
491498 address = SGF.B .createMarkUninitializedVar (vd, address);
492- DestroyCleanup = SGF.enterDormantTemporaryCleanup (address, lowering);
499+ DestroyCleanup = SGF.enterDormantTemporaryCleanup (address, * lowering);
493500 SGF.VarLocs [vd] = SILGenFunction::VarLoc::get (address);
494- } else if (!lowering. isTrivial ()) {
501+ } else if (!lowering-> isTrivial ()) {
495502 // Push a cleanup to destroy the let declaration. This has to be
496503 // inactive until the variable is initialized: if control flow exits the
497504 // before the value is bound, we don't want to destroy the value.
@@ -554,31 +561,68 @@ class LetValueInitialization : public Initialization {
554561 address = value;
555562 SILLocation PrologueLoc (vd);
556563
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+ }
572584
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);
577624 value = SGF.B .createMarkMustCheckInst (
578625 PrologueLoc, value, MarkMustCheckInst::CheckKind::NoImplicitCopy);
579- } else {
580- value = SILValue (
581- SGF.B .createBeginBorrow (PrologueLoc, value, /* isLexical*/ true ));
582626 }
583627 }
584628 }
@@ -608,7 +652,8 @@ class LetValueInitialization : public Initialization {
608652 // Disable the rvalue expression cleanup, since the let value
609653 // initialization has a cleanup that lives for the entire scope of the
610654 // let declaration.
611- bindValue (value.forward (SGF), SGF, value.isPlusOne (SGF));
655+ bool isPlusOne = value.isPlusOne (SGF);
656+ bindValue (value.forward (SGF), SGF, isPlusOne);
612657 } else {
613658 // Disable the expression cleanup of the copy, since the let value
614659 // initialization has a cleanup that lives for the entire scope of the
@@ -631,8 +676,9 @@ class LetValueInitialization : public Initialization {
631676 SGF.Cleanups .forwardCleanup (cleanup);
632677
633678 // Activate the destroy cleanup.
634- if (DestroyCleanup != CleanupHandle::invalid ())
679+ if (DestroyCleanup != CleanupHandle::invalid ()) {
635680 SGF.Cleanups .setCleanupState (DestroyCleanup, CleanupState::Active);
681+ }
636682
637683 DidFinish = true ;
638684 }
@@ -1795,6 +1841,9 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
17951841 return ;
17961842 }
17971843
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.
17981847 if (auto *bbi = dyn_cast<BeginBorrowInst>(Val.getDefiningInstruction ())) {
17991848 B.createEndBorrow (silLoc, bbi);
18001849 B.emitDestroyValueOperation (silLoc, bbi->getOperand ());
@@ -1814,6 +1863,31 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
18141863 }
18151864 }
18161865 }
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+ }
18171891 }
18181892 }
18191893 }
0 commit comments