Skip to content

Commit f735eda

Browse files
authored
Merge pull request #62567 from gottesmm/pr-aff949c3a3e3aaf7839d4462bd96b8eb60c06f97
[move-only-object] Teach move only object verifier how to emit proper errors for closure/defer uses
2 parents 70d4b46 + 0735f9f commit f735eda

File tree

8 files changed

+535
-250
lines changed

8 files changed

+535
-250
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,8 @@ ERROR(sil_moveonlychecker_value_used_after_consume, none,
731731
"'%0' used after consume. Lifetime extension of variable requires a copy", (StringRef))
732732
ERROR(sil_moveonlychecker_guaranteed_value_consumed, none,
733733
"'%0' has guaranteed ownership but was consumed", (StringRef))
734+
ERROR(sil_moveonlychecker_guaranteed_value_captured_by_closure, none,
735+
"'%0' has guaranteed ownership but was consumed due to being captured by a closure", (StringRef))
734736
ERROR(sil_moveonlychecker_inout_not_reinitialized_before_end_of_function, none,
735737
"'%0' consumed but not reinitialized before end of function", (StringRef))
736738
ERROR(sil_moveonlychecker_value_consumed_in_a_loop, none,
@@ -740,6 +742,8 @@ ERROR(sil_moveonlychecker_exclusivity_violation, none,
740742

741743
NOTE(sil_moveonlychecker_consuming_use_here, none,
742744
"consuming use", ())
745+
NOTE(sil_moveonlychecker_consuming_closure_use_here, none,
746+
"closure capture", ())
743747
NOTE(sil_moveonlychecker_nonconsuming_use_here, none,
744748
"non-consuming use", ())
745749
ERROR(sil_moveonlychecker_not_understand_no_implicit_copy, none,

lib/SILGen/SILGenBuilder.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,3 +952,12 @@ SILGenBuilder::createMarkMustCheckInst(SILLocation loc, ManagedValue value,
952952
loc, value.forward(getSILGenFunction()), kind);
953953
return cloner.clone(mdi);
954954
}
955+
956+
ManagedValue SILGenBuilder::emitCopyValueOperation(SILLocation loc,
957+
ManagedValue value) {
958+
auto cvi = SILBuilder::emitCopyValueOperation(loc, value.getValue());
959+
// Trivial type.
960+
if (cvi == value.getValue())
961+
return value;
962+
return SGF.emitManagedRValueWithCleanup(cvi);
963+
}

lib/SILGen/SILGenBuilder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,9 @@ class SILGenBuilder : public SILBuilder {
430430
using SILBuilder::createMarkMustCheckInst;
431431
ManagedValue createMarkMustCheckInst(SILLocation loc, ManagedValue value,
432432
MarkMustCheckInst::CheckKind kind);
433+
434+
using SILBuilder::emitCopyValueOperation;
435+
ManagedValue emitCopyValueOperation(SILLocation Loc, ManagedValue v);
433436
};
434437

435438
} // namespace Lowering

lib/SILGen/SILGenProlog.cpp

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -520,34 +520,47 @@ static void emitCaptureArguments(SILGenFunction &SGF,
520520
auto &lowering = SGF.getTypeLowering(type);
521521
// Constant decls are captured by value.
522522
SILType ty = lowering.getLoweredType();
523-
SILValue val = SGF.F.begin()->createFunctionArgument(ty, VD);
524-
525-
bool NeedToDestroyValueAtExit = false;
523+
ManagedValue val = ManagedValue::forUnmanaged(
524+
SGF.F.begin()->createFunctionArgument(ty, VD));
526525

527526
// If the original variable was settable, then Sema will have treated the
528527
// VarDecl as an lvalue, even in the closure's use. As such, we need to
529528
// allow formation of the address for this captured value. Create a
530529
// temporary within the closure to provide this address.
531530
if (VD->isSettable(VD->getDeclContext())) {
532-
auto addr = SGF.emitTemporaryAllocation(VD, ty);
531+
auto addr = SGF.emitTemporary(VD, lowering);
533532
// We have created a copy that needs to be destroyed.
534533
val = SGF.B.emitCopyValueOperation(Loc, val);
535-
NeedToDestroyValueAtExit = true;
536-
lowering.emitStore(SGF.B, VD, val, addr, StoreOwnershipQualifier::Init);
537-
val = addr;
534+
// We use the SILValue version of this because the SILGenBuilder version
535+
// will create a cloned cleanup, which we do not want since our temporary
536+
// already has a cleanup.
537+
//
538+
// MG: Is this the right semantics for createStore? Seems like that
539+
// should be potentially a different API.
540+
SGF.B.emitStoreValueOperation(VD, val.forward(SGF), addr->getAddress(),
541+
StoreOwnershipQualifier::Init);
542+
addr->finishInitialization(SGF);
543+
val = addr->getManagedAddress();
544+
}
545+
546+
// If this constant is a move only type, we need to add no_copy checking to
547+
// ensure that we do not consume this captured value in the function. This
548+
// is because closures can be invoked multiple times which is inconsistent
549+
// with consuming the move only type.
550+
if (val.getType().isMoveOnly()) {
551+
val = val.ensurePlusOne(SGF, Loc);
552+
val = SGF.B.createMarkMustCheckInst(Loc, val,
553+
MarkMustCheckInst::CheckKind::NoCopy);
538554
}
539555

540-
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(val);
541-
if (auto *AllocStack = dyn_cast<AllocStackInst>(val))
556+
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(val.getValue());
557+
if (auto *AllocStack = dyn_cast<AllocStackInst>(val.getValue())) {
542558
AllocStack->setArgNo(ArgNo);
543-
else {
559+
} else {
544560
SILDebugVariable DbgVar(VD->isLet(), ArgNo);
545-
SGF.B.createDebugValue(Loc, val, DbgVar);
561+
SGF.B.createDebugValue(Loc, val.getValue(), DbgVar);
546562
}
547563

548-
// TODO: Closure contexts should always be guaranteed.
549-
if (NeedToDestroyValueAtExit && !lowering.isTrivial())
550-
SGF.enterDestroyCleanup(val);
551564
break;
552565
}
553566

0 commit comments

Comments
 (0)