Skip to content

Commit 2d89b20

Browse files
authored
Merge pull request #65645 from gottesmm/release/5.9/rdar105106470
[5.9][move-only] Address Only Batched Fixes
2 parents 251b719 + f52efde commit 2d89b20

File tree

12 files changed

+1779
-213
lines changed

12 files changed

+1779
-213
lines changed

include/swift/SIL/SILUndef.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ class SILUndef : public ValueBase {
3030
void operator delete(void *, size_t) = delete;
3131

3232
static SILUndef *get(SILType ty, SILModule &m);
33+
34+
/// Return a SILUndef with the same type as the passed in value.
35+
static SILUndef *get(SILValue value) {
36+
return SILUndef::get(value->getType(), *value->getModule());
37+
}
38+
3339
static SILUndef *get(SILType ty, const SILFunction &f);
3440

3541
template <class OwnerTy>

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2384,7 +2384,7 @@ struct DeallocatorConventions : Conventions {
23842384

23852385
ParameterConvention
23862386
getIndirectSelfParameter(const AbstractionPattern &type) const override {
2387-
llvm_unreachable("Deallocators do not have indirect self parameters");
2387+
return ParameterConvention::Indirect_In;
23882388
}
23892389

23902390
static bool classof(const Conventions *C) {

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ struct ImmutableAddressUseVerifier {
674674
case SILInstructionKind::IndexAddrInst:
675675
case SILInstructionKind::TailAddrInst:
676676
case SILInstructionKind::IndexRawPointerInst:
677+
case SILInstructionKind::MarkMustCheckInst:
677678
// Add these to our worklist.
678679
for (auto result : inst->getResults()) {
679680
llvm::copy(result->getUses(), std::back_inserter(worklist));

lib/SILGen/SILGenLValue.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3183,7 +3183,8 @@ RValue SILGenFunction::emitRValueForNonMemberVarDecl(SILLocation loc,
31833183
SILValue accessAddr = UnenforcedFormalAccess::enter(*this, loc, destAddr,
31843184
SILAccessKind::Read);
31853185

3186-
if (accessAddr->getType().isMoveOnly()) {
3186+
if (accessAddr->getType().isMoveOnly() &&
3187+
!isa<MarkMustCheckInst>(accessAddr)) {
31873188
// When loading an rvalue, we should never need to modify the place
31883189
// we're loading from.
31893190
accessAddr = B.createMarkMustCheckInst(

lib/SILGen/SILGenProlog.cpp

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ static void diagnose(ASTContext &Context, SourceLoc loc, Diag<T...> diag,
4040

4141
SILValue SILGenFunction::emitSelfDeclForDestructor(VarDecl *selfDecl) {
4242
// Emit the implicit 'self' argument.
43-
SILType selfType = getLoweredLoadableType(selfDecl->getType());
43+
SILType selfType = getLoweredType(selfDecl->getType());
4444
SILValue selfValue = F.begin()->createFunctionArgument(selfType, selfDecl);
4545

4646
// If we have a move only type, then mark it with mark_must_check so we can't
@@ -748,7 +748,6 @@ class ArgumentInitHelper {
748748
/// if not null.
749749
void makeArgumentIntoBinding(SILLocation loc, ParamDecl *pd) {
750750
ManagedValue argrv = makeArgument(loc, pd);
751-
752751
SILValue value = argrv.getValue();
753752
if (pd->isInOut()) {
754753
assert(argrv.getType().isAddress() && "expected inout to be address");
@@ -768,18 +767,52 @@ class ArgumentInitHelper {
768767
if (!argrv.getType().isAddress()) {
769768
// NOTE: We setup SGF.VarLocs[pd] in updateArgumentValueForBinding.
770769
updateArgumentValueForBinding(argrv, loc, pd, value, varinfo);
771-
} else {
772-
if (auto *allocStack = dyn_cast<AllocStackInst>(value)) {
773-
allocStack->setArgNo(ArgNo);
774-
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(
775-
SGF.getModule()) &&
776-
SGF.F.getLifetime(pd, value->getType()).isLexical())
777-
allocStack->setIsLexical();
778-
} else {
779-
SGF.B.createDebugValueAddr(loc, value, varinfo);
780-
}
770+
return;
771+
}
772+
773+
if (auto *allocStack = dyn_cast<AllocStackInst>(value)) {
774+
allocStack->setArgNo(ArgNo);
775+
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(
776+
SGF.getModule()) &&
777+
SGF.F.getLifetime(pd, value->getType()).isLexical())
778+
allocStack->setIsLexical();
781779
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value);
780+
return;
781+
}
782+
783+
if (value->getType().isMoveOnly()) {
784+
switch (pd->getValueOwnership()) {
785+
case ValueOwnership::Default:
786+
if (pd->isSelfParameter()) {
787+
assert(!isa<MarkMustCheckInst>(value) &&
788+
"Should not have inserted mark must check inst in EmitBBArgs");
789+
if (!pd->isInOut()) {
790+
value = SGF.B.createMarkMustCheckInst(
791+
loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
792+
}
793+
} else {
794+
assert(isa<MarkMustCheckInst>(value) &&
795+
"Should have inserted mark must check inst in EmitBBArgs");
796+
}
797+
break;
798+
case ValueOwnership::InOut:
799+
assert(isa<MarkMustCheckInst>(value) &&
800+
"Expected mark must check inst with inout to be handled in "
801+
"emitBBArgs earlier");
802+
break;
803+
case ValueOwnership::Owned:
804+
value = SGF.B.createMarkMustCheckInst(
805+
loc, value, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
806+
break;
807+
case ValueOwnership::Shared:
808+
value = SGF.B.createMarkMustCheckInst(
809+
loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
810+
break;
811+
}
782812
}
813+
814+
SGF.B.createDebugValueAddr(loc, value, varinfo);
815+
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value);
783816
}
784817

785818
void emitParam(ParamDecl *PD) {

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,19 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
15111511
assert(op->getOperandNumber() == CopyAddrInst::Src &&
15121512
"Should have dest above in memInstMust{Rei,I}nitialize");
15131513

1514+
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
1515+
if (!leafRange)
1516+
return false;
1517+
1518+
// If we have a non-move only type, just treat this as a liveness use.
1519+
if (!copyAddr->getSrc()->getType().isMoveOnly()) {
1520+
LLVM_DEBUG(llvm::dbgs()
1521+
<< "Found copy of copyable type. Treating as liveness use! "
1522+
<< *user);
1523+
useState.livenessUses.insert({user, *leafRange});
1524+
return true;
1525+
}
1526+
15141527
if (markedValue->getCheckKind() ==
15151528
MarkMustCheckInst::CheckKind::NoConsumeOrAssign) {
15161529
LLVM_DEBUG(llvm::dbgs()
@@ -1520,17 +1533,11 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
15201533
return true;
15211534
}
15221535

1523-
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
1524-
if (!leafRange)
1525-
return false;
1526-
15271536
// TODO: Add borrow checking here like below.
15281537

15291538
// TODO: Add destructure deinit checking here once address only checking is
15301539
// completely brought up.
15311540

1532-
// TODO: Add check here that we don't error on trivial/copyable types.
1533-
15341541
if (copyAddr->isTakeOfSrc()) {
15351542
LLVM_DEBUG(llvm::dbgs() << "Found take: " << *user);
15361543
useState.takeInsts.insert({user, *leafRange});
@@ -1721,9 +1728,30 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
17211728
// Now that we have handled or loadTakeOrCopy, we need to now track our
17221729
// additional pure takes.
17231730
if (::memInstMustConsume(op)) {
1731+
// If we don't have a consumeable and assignable check kind, then we can't
1732+
// consume. Emit an error.
1733+
//
1734+
// NOTE: Since SILGen eagerly loads loadable types from memory, this
1735+
// generally will only handle address only types.
1736+
if (markedValue->getCheckKind() !=
1737+
MarkMustCheckInst::CheckKind::ConsumableAndAssignable) {
1738+
auto *fArg = dyn_cast<SILFunctionArgument>(
1739+
stripAccessMarkers(markedValue->getOperand()));
1740+
if (fArg && fArg->isClosureCapture() && fArg->getType().isAddress()) {
1741+
moveChecker.diagnosticEmitter.emitPromotedBoxArgumentError(markedValue,
1742+
fArg);
1743+
} else {
1744+
moveChecker.diagnosticEmitter
1745+
.emitAddressEscapingClosureCaptureLoadedAndConsumed(markedValue);
1746+
}
1747+
emittedEarlyDiagnostic = true;
1748+
return true;
1749+
}
1750+
17241751
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
17251752
if (!leafRange)
17261753
return false;
1754+
17271755
LLVM_DEBUG(llvm::dbgs() << "Pure consuming use: " << *user);
17281756
useState.takeInsts.insert({user, *leafRange});
17291757
return true;
@@ -2423,7 +2451,6 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck(
24232451
LLVM_DEBUG(llvm::dbgs() << "Failed access path visit: " << *markedAddress);
24242452
return false;
24252453
}
2426-
addressUseState.initializeInOutTermUsers();
24272454

24282455
// If we found a load [copy] or copy_addr that requires multiple copies or an
24292456
// exclusivity error, then we emitted an early error. Bail now and allow the
@@ -2438,9 +2465,14 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck(
24382465
if (diagCount != diagnosticEmitter.getDiagnosticCount())
24392466
return true;
24402467

2441-
// Then check if we emitted an error. If we did not, return true.
2442-
if (diagCount != diagnosticEmitter.getDiagnosticCount())
2443-
return true;
2468+
// Now that we know that we have run our visitor and did not emit any errors
2469+
// and successfully visited everything, see if have any
2470+
// assignable_but_not_consumable of address only types that are consumed.
2471+
//
2472+
// DISCUSSION: For non address only types, this is not an issue since we
2473+
// eagerly load
2474+
2475+
addressUseState.initializeInOutTermUsers();
24442476

24452477
//===---
24462478
// Liveness Checking

test/Interpreter/moveonly.swift

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ Tests.test("global destroyed once") {
4545
do {
4646
global = FD()
4747
}
48-
expectEqual(0, LifetimeTracked.instances)
48+
expectEqual(0, LifetimeTracked.instances)
4949
}
5050

5151
@_moveOnly
@@ -104,3 +104,31 @@ Tests.test("empty struct") {
104104
let _ = consume e
105105
}
106106
}
107+
108+
protocol P {
109+
var name: String { get }
110+
}
111+
112+
Tests.test("AddressOnly") {
113+
class Klass : P {
114+
var name: String { "myName" }
115+
}
116+
117+
@_moveOnly
118+
struct S<T : P> {
119+
var t: T
120+
}
121+
122+
let e = S(t: Klass())
123+
expectEqual(e.t.name, "myName")
124+
125+
func testGeneric<T : P>(_ x: borrowing S<T>) {
126+
expectEqual(x.t.name, "myName")
127+
}
128+
testGeneric(e)
129+
130+
if e.t.name.count == 5 {
131+
let _ = consume e
132+
}
133+
}
134+

0 commit comments

Comments
 (0)