Skip to content

Commit cb6e5d1

Browse files
authored
Merge pull request #61964 from gottesmm/pr-140968cb0578adfb1af5718b8468c8c391695642
[move-only] Teach the object/address move operator checker to not check move only types.
2 parents 4b23a9f + 26db1f2 commit cb6e5d1

File tree

6 files changed

+78
-13
lines changed

6 files changed

+78
-13
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "swift/AST/Types.h"
4242
#include "swift/Basic/SourceManager.h"
4343
#include "swift/Basic/type_traits.h"
44+
#include "swift/SIL/Consumption.h"
4445
#include "swift/SIL/DynamicCasts.h"
4546
#include "swift/SIL/SILArgument.h"
4647
#include "swift/SIL/SILInstruction.h"
@@ -5934,7 +5935,11 @@ RValue RValueEmitter::visitMoveExpr(MoveExpr *E, SGFContext C) {
59345935
}
59355936

59365937
// If we aren't loadable, then create a temporary initialization and
5937-
// mark_unresolved_move into that.
5938+
// mark_unresolved_move into that if we have a copyable type if we have a move
5939+
// only, just add a copy_addr init.
5940+
//
5941+
// The reason why we do this is that we only use mark_unresolved_move_addr and
5942+
// the move operator checker for copyable values.
59385943
std::unique_ptr<TemporaryInitialization> optTemp;
59395944
optTemp = SGF.emitTemporary(E, SGF.getTypeLowering(subType));
59405945
SILValue toAddr = optTemp->getAddressForInPlaceInitialization(SGF, E);
@@ -5945,7 +5950,12 @@ RValue RValueEmitter::visitMoveExpr(MoveExpr *E, SGFContext C) {
59455950
SGF.emitRValue(subExpr, SGFContext(SGFContext::AllowImmediatePlusZero))
59465951
.getAsSingleValue(SGF, subExpr);
59475952
assert(mv.getType().isAddress());
5948-
SGF.B.createMarkUnresolvedMoveAddr(subExpr, mv.getValue(), toAddr);
5953+
if (mv.getType().isMoveOnly()) {
5954+
SGF.B.createCopyAddr(subExpr, mv.getValue(), toAddr, IsNotTake,
5955+
IsInitialization);
5956+
} else {
5957+
SGF.B.createMarkUnresolvedMoveAddr(subExpr, mv.getValue(), toAddr);
5958+
}
59495959
optTemp->finishInitialization(SGF);
59505960
return RValue(SGF, {optTemp->getManagedAddress()}, subType.getASTType());
59515961
}

lib/SILGen/SILGenLValue.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/AST/GenericEnvironment.h"
3131
#include "swift/AST/PropertyWrappers.h"
3232
#include "swift/AST/TypeCheckRequests.h"
33+
#include "swift/SIL/Consumption.h"
3334
#include "swift/SIL/InstructionUtils.h"
3435
#include "swift/SIL/MemAccessUtils.h"
3536
#include "swift/SIL/PrettyStackTrace.h"
@@ -3914,11 +3915,21 @@ LValue SILGenLValue::visitMoveExpr(MoveExpr *e, SGFAccessKind accessKind,
39143915

39153916
ManagedValue addr = SGF.emitAddressOfLValue(e, std::move(baseLV));
39163917

3917-
// Now create the temporary and
3918+
// Now create the temporary and move our value into there.
39183919
auto temp =
39193920
SGF.emitFormalAccessTemporary(e, SGF.F.getTypeLowering(addr.getType()));
39203921
auto toAddr = temp->getAddressForInPlaceInitialization(SGF, e);
3921-
SGF.B.createMarkUnresolvedMoveAddr(e, addr.getValue(), toAddr);
3922+
3923+
// If we have a move only type, we use a copy_addr that will be handled by the
3924+
// address move only checker. If we have a copyable type, we need to use a
3925+
// mark_unresolved_move_addr to ensure that the move operator checker performs
3926+
// the relevant checking.
3927+
if (addr.getType().isMoveOnly()) {
3928+
SGF.B.createCopyAddr(e, addr.getValue(), toAddr, IsNotTake,
3929+
IsInitialization);
3930+
} else {
3931+
SGF.B.createMarkUnresolvedMoveAddr(e, addr.getValue(), toAddr);
3932+
}
39223933
temp->finishInitialization(SGF);
39233934

39243935
// Now return the temporary in a value component.

lib/SILOptimizer/Mandatory/MoveKillsCopyableValuesChecker.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,8 @@ bool MoveKillsCopyableValuesChecker::check() {
400400
SmallSetVector<SILValue, 32> valuesToCheck;
401401

402402
for (auto *arg : fn->getEntryBlock()->getSILFunctionArguments()) {
403-
if (arg->getOwnershipKind() == OwnershipKind::Owned) {
403+
if (arg->getOwnershipKind() == OwnershipKind::Owned &&
404+
!arg->getType().isMoveOnly()) {
404405
LLVM_DEBUG(llvm::dbgs() << "Found owned arg to check: " << *arg);
405406
valuesToCheck.insert(arg);
406407
}
@@ -409,7 +410,7 @@ bool MoveKillsCopyableValuesChecker::check() {
409410
for (auto &block : *fn) {
410411
for (auto &ii : block) {
411412
if (auto *bbi = dyn_cast<BeginBorrowInst>(&ii)) {
412-
if (bbi->isLexical()) {
413+
if (bbi->isLexical() && !bbi->getType().isMoveOnly()) {
413414
LLVM_DEBUG(llvm::dbgs()
414415
<< "Found lexical lifetime to check: " << *bbi);
415416
valuesToCheck.insert(bbi);
@@ -551,19 +552,28 @@ class MoveKillsCopyableValuesCheckerPass : public SILFunctionTransform {
551552
SILAnalysis::InvalidationKind::BranchesAndInstructions);
552553
}
553554

554-
// Now search through our function one last time and any move_value
555-
// [allows_diagnostics] that remain are ones that we did not know how to
556-
// check so emit a diagnostic so the user doesn't assume that they have
557-
// guarantees.
555+
// Now search through our function one last time and:
556+
//
557+
// 1. Given any move_value on a move only type, just unset the allows
558+
// diagnostics flag. The move checker will have emitted any errors caused
559+
// by our move [allows_diagnostic] earlier in the compilation pipeline.
560+
//
561+
// 2. Any move_value [allows_diagnostics] that remain that are not on a move
562+
// only type are ones that we did not know how to check so emit a
563+
// diagnostic so the user doesn't assume that they have guarantees.
558564
//
559565
// TODO: Emit specific diagnostics here (e.x.: _move of global).
560-
if (DisableUnhandledMoveDiagnostic)
561-
return;
562566
for (auto &block : *fn) {
563567
for (auto &inst : block) {
564568
if (auto *mvi = dyn_cast<MoveValueInst>(&inst)) {
565569
if (mvi->getAllowDiagnostics()) {
566-
emitUnsupportedUseCaseError(mvi);
570+
if (mvi->getType().isMoveOnly()) {
571+
mvi->setAllowsDiagnostics(false);
572+
continue;
573+
}
574+
575+
if (!DisableUnhandledMoveDiagnostic)
576+
emitUnsupportedUseCaseError(mvi);
567577
}
568578
}
569579
}

test/SILOptimizer/moveonly_addresschecker_diagnostics.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,3 +2061,15 @@ public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: inout Klass) {
20612061
}
20622062
f()
20632063
}
2064+
2065+
/////////////////////////////
2066+
// Tests For Move Operator //
2067+
/////////////////////////////
2068+
2069+
func moveOperatorTest(_ k: __owned Klass) {
2070+
var k2 = k // expected-error {{'k2' consumed more than once}}
2071+
k2 = Klass()
2072+
let k3 = _move k2 // expected-note {{consuming use}}
2073+
let _ = _move k2 // expected-note {{consuming use}}
2074+
let _ = k3
2075+
}

test/SILOptimizer/moveonly_objectchecker_diagnostics.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,3 +2326,14 @@ public func closureAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned
23262326
f()
23272327
print(x2) // expected-note {{consuming use}}
23282328
}
2329+
2330+
/////////////////////////////
2331+
// Tests For Move Operator //
2332+
/////////////////////////////
2333+
2334+
func moveOperatorTest(_ k: __owned Klass) {
2335+
let k2 = k // expected-error {{'k2' consumed more than once}}
2336+
let k3 = _move k2 // expected-note {{consuming use}}
2337+
let _ = _move k2 // expected-note {{consuming use}}
2338+
let _ = k3
2339+
}

test/SILOptimizer/noimplicitcopy.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2212,3 +2212,14 @@ public func closureAndClosureCaptureClassOwnedArgUseAfterConsume2(@_noImplicitCo
22122212
f()
22132213
print(x2) // expected-note {{consuming use}}
22142214
}
2215+
2216+
/////////////////////////////
2217+
// Tests For Move Operator //
2218+
/////////////////////////////
2219+
2220+
func moveOperatorTest(_ k: __owned Klass) {
2221+
@_noImplicitCopy let k2 = k // expected-error {{'k2' consumed more than once}}
2222+
@_noImplicitCopy let k3 = _move k2 // expected-note {{consuming use}}
2223+
let _ = _move k2 // expected-note {{consuming use}}
2224+
let _ = k3
2225+
}

0 commit comments

Comments
 (0)