mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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
This commit is contained in:
@@ -731,6 +731,8 @@ ERROR(sil_moveonlychecker_value_used_after_consume, none,
|
|||||||
"'%0' used after consume. Lifetime extension of variable requires a copy", (StringRef))
|
"'%0' used after consume. Lifetime extension of variable requires a copy", (StringRef))
|
||||||
ERROR(sil_moveonlychecker_guaranteed_value_consumed, none,
|
ERROR(sil_moveonlychecker_guaranteed_value_consumed, none,
|
||||||
"'%0' has guaranteed ownership but was consumed", (StringRef))
|
"'%0' has guaranteed ownership but was consumed", (StringRef))
|
||||||
|
ERROR(sil_moveonlychecker_guaranteed_value_captured_by_closure, none,
|
||||||
|
"'%0' has guaranteed ownership but was consumed due to being captured by a closure", (StringRef))
|
||||||
ERROR(sil_moveonlychecker_inout_not_reinitialized_before_end_of_function, none,
|
ERROR(sil_moveonlychecker_inout_not_reinitialized_before_end_of_function, none,
|
||||||
"'%0' consumed but not reinitialized before end of function", (StringRef))
|
"'%0' consumed but not reinitialized before end of function", (StringRef))
|
||||||
ERROR(sil_moveonlychecker_value_consumed_in_a_loop, none,
|
ERROR(sil_moveonlychecker_value_consumed_in_a_loop, none,
|
||||||
@@ -740,6 +742,8 @@ ERROR(sil_moveonlychecker_exclusivity_violation, none,
|
|||||||
|
|
||||||
NOTE(sil_moveonlychecker_consuming_use_here, none,
|
NOTE(sil_moveonlychecker_consuming_use_here, none,
|
||||||
"consuming use", ())
|
"consuming use", ())
|
||||||
|
NOTE(sil_moveonlychecker_consuming_closure_use_here, none,
|
||||||
|
"closure capture", ())
|
||||||
NOTE(sil_moveonlychecker_nonconsuming_use_here, none,
|
NOTE(sil_moveonlychecker_nonconsuming_use_here, none,
|
||||||
"non-consuming use", ())
|
"non-consuming use", ())
|
||||||
ERROR(sil_moveonlychecker_not_understand_no_implicit_copy, none,
|
ERROR(sil_moveonlychecker_not_understand_no_implicit_copy, none,
|
||||||
|
|||||||
@@ -952,3 +952,12 @@ SILGenBuilder::createMarkMustCheckInst(SILLocation loc, ManagedValue value,
|
|||||||
loc, value.forward(getSILGenFunction()), kind);
|
loc, value.forward(getSILGenFunction()), kind);
|
||||||
return cloner.clone(mdi);
|
return cloner.clone(mdi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ManagedValue SILGenBuilder::emitCopyValueOperation(SILLocation loc,
|
||||||
|
ManagedValue value) {
|
||||||
|
auto cvi = SILBuilder::emitCopyValueOperation(loc, value.getValue());
|
||||||
|
// Trivial type.
|
||||||
|
if (cvi == value.getValue())
|
||||||
|
return value;
|
||||||
|
return SGF.emitManagedRValueWithCleanup(cvi);
|
||||||
|
}
|
||||||
|
|||||||
@@ -430,6 +430,9 @@ public:
|
|||||||
using SILBuilder::createMarkMustCheckInst;
|
using SILBuilder::createMarkMustCheckInst;
|
||||||
ManagedValue createMarkMustCheckInst(SILLocation loc, ManagedValue value,
|
ManagedValue createMarkMustCheckInst(SILLocation loc, ManagedValue value,
|
||||||
MarkMustCheckInst::CheckKind kind);
|
MarkMustCheckInst::CheckKind kind);
|
||||||
|
|
||||||
|
using SILBuilder::emitCopyValueOperation;
|
||||||
|
ManagedValue emitCopyValueOperation(SILLocation Loc, ManagedValue v);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Lowering
|
} // namespace Lowering
|
||||||
|
|||||||
@@ -520,34 +520,47 @@ static void emitCaptureArguments(SILGenFunction &SGF,
|
|||||||
auto &lowering = SGF.getTypeLowering(type);
|
auto &lowering = SGF.getTypeLowering(type);
|
||||||
// Constant decls are captured by value.
|
// Constant decls are captured by value.
|
||||||
SILType ty = lowering.getLoweredType();
|
SILType ty = lowering.getLoweredType();
|
||||||
SILValue val = SGF.F.begin()->createFunctionArgument(ty, VD);
|
ManagedValue val = ManagedValue::forUnmanaged(
|
||||||
|
SGF.F.begin()->createFunctionArgument(ty, VD));
|
||||||
bool NeedToDestroyValueAtExit = false;
|
|
||||||
|
|
||||||
// If the original variable was settable, then Sema will have treated the
|
// If the original variable was settable, then Sema will have treated the
|
||||||
// VarDecl as an lvalue, even in the closure's use. As such, we need to
|
// VarDecl as an lvalue, even in the closure's use. As such, we need to
|
||||||
// allow formation of the address for this captured value. Create a
|
// allow formation of the address for this captured value. Create a
|
||||||
// temporary within the closure to provide this address.
|
// temporary within the closure to provide this address.
|
||||||
if (VD->isSettable(VD->getDeclContext())) {
|
if (VD->isSettable(VD->getDeclContext())) {
|
||||||
auto addr = SGF.emitTemporaryAllocation(VD, ty);
|
auto addr = SGF.emitTemporary(VD, lowering);
|
||||||
// We have created a copy that needs to be destroyed.
|
// We have created a copy that needs to be destroyed.
|
||||||
val = SGF.B.emitCopyValueOperation(Loc, val);
|
val = SGF.B.emitCopyValueOperation(Loc, val);
|
||||||
NeedToDestroyValueAtExit = true;
|
// We use the SILValue version of this because the SILGenBuilder version
|
||||||
lowering.emitStore(SGF.B, VD, val, addr, StoreOwnershipQualifier::Init);
|
// will create a cloned cleanup, which we do not want since our temporary
|
||||||
val = addr;
|
// already has a cleanup.
|
||||||
|
//
|
||||||
|
// MG: Is this the right semantics for createStore? Seems like that
|
||||||
|
// should be potentially a different API.
|
||||||
|
SGF.B.emitStoreValueOperation(VD, val.forward(SGF), addr->getAddress(),
|
||||||
|
StoreOwnershipQualifier::Init);
|
||||||
|
addr->finishInitialization(SGF);
|
||||||
|
val = addr->getManagedAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(val);
|
// If this constant is a move only type, we need to add no_copy checking to
|
||||||
if (auto *AllocStack = dyn_cast<AllocStackInst>(val))
|
// ensure that we do not consume this captured value in the function. This
|
||||||
|
// is because closures can be invoked multiple times which is inconsistent
|
||||||
|
// with consuming the move only type.
|
||||||
|
if (val.getType().isMoveOnly()) {
|
||||||
|
val = val.ensurePlusOne(SGF, Loc);
|
||||||
|
val = SGF.B.createMarkMustCheckInst(Loc, val,
|
||||||
|
MarkMustCheckInst::CheckKind::NoCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(val.getValue());
|
||||||
|
if (auto *AllocStack = dyn_cast<AllocStackInst>(val.getValue())) {
|
||||||
AllocStack->setArgNo(ArgNo);
|
AllocStack->setArgNo(ArgNo);
|
||||||
else {
|
} else {
|
||||||
SILDebugVariable DbgVar(VD->isLet(), ArgNo);
|
SILDebugVariable DbgVar(VD->isLet(), ArgNo);
|
||||||
SGF.B.createDebugValue(Loc, val, DbgVar);
|
SGF.B.createDebugValue(Loc, val.getValue(), DbgVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Closure contexts should always be guaranteed.
|
|
||||||
if (NeedToDestroyValueAtExit && !lowering.isTrivial())
|
|
||||||
SGF.enterDestroyCleanup(val);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,90 @@
|
|||||||
using namespace swift;
|
using namespace swift;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Utilities
|
// MARK: Checker State
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/// Wrapper around CanonicalizeOSSALifetime that we use to specialize its
|
||||||
|
/// interface for our purposes.
|
||||||
|
struct OSSACanonicalizer {
|
||||||
|
/// A per mark must check, vector of uses that copy propagation says need a
|
||||||
|
/// copy and thus are not final consuming uses.
|
||||||
|
SmallVector<Operand *, 32> consumingUsesNeedingCopy;
|
||||||
|
|
||||||
|
/// A per mark must check, vector of consuming uses that copy propagation says
|
||||||
|
/// are actual last uses.
|
||||||
|
SmallVector<Operand *, 32> finalConsumingUses;
|
||||||
|
|
||||||
|
/// The actual canonicalizer that we use.
|
||||||
|
///
|
||||||
|
/// We mark this Optional to avoid UB behavior caused by us needing to
|
||||||
|
/// initialize CanonicalizeOSSALifetime with parts of OSSACanoncializer
|
||||||
|
/// (specifically with state in our arrays) before the actual constructor has
|
||||||
|
/// run. Specifically this avoids:
|
||||||
|
///
|
||||||
|
/// 11.9.5p1 class.cdtor: For an object with a non-trivial constructor,
|
||||||
|
/// referring to any non-static member or base class of the object before the
|
||||||
|
/// constructor begins execution results in undefined behavior.
|
||||||
|
Optional<CanonicalizeOSSALifetime> canonicalizer;
|
||||||
|
|
||||||
|
OSSACanonicalizer(SILFunction *fn,
|
||||||
|
NonLocalAccessBlockAnalysis *accessBlockAnalysis,
|
||||||
|
DominanceInfo *domTree, InstructionDeleter &deleter) {
|
||||||
|
auto foundConsumingUseNeedingCopy = std::function<void(Operand *)>(
|
||||||
|
[&](Operand *use) { consumingUsesNeedingCopy.push_back(use); });
|
||||||
|
auto foundConsumingUseNotNeedingCopy = std::function<void(Operand *)>(
|
||||||
|
[&](Operand *use) { finalConsumingUses.push_back(use); });
|
||||||
|
|
||||||
|
canonicalizer.emplace(
|
||||||
|
false /*pruneDebugMode*/, !fn->shouldOptimize() /*maximizeLifetime*/,
|
||||||
|
accessBlockAnalysis, domTree, deleter, foundConsumingUseNeedingCopy,
|
||||||
|
foundConsumingUseNotNeedingCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
consumingUsesNeedingCopy.clear();
|
||||||
|
finalConsumingUses.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canonicalize(MarkMustCheckInst *markedValue) {
|
||||||
|
return canonicalizer->canonicalizeValueLifetime(markedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool foundAnyConsumingUses() const {
|
||||||
|
return consumingUsesNeedingCopy.size() || finalConsumingUses.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool foundConsumingUseRequiringCopy() const {
|
||||||
|
return consumingUsesNeedingCopy.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasPartialApplyConsumingUse() const {
|
||||||
|
return llvm::any_of(consumingUsesNeedingCopy,
|
||||||
|
[](Operand *use) {
|
||||||
|
return isa<PartialApplyInst>(use->getUser());
|
||||||
|
}) ||
|
||||||
|
llvm::any_of(finalConsumingUses, [](Operand *use) {
|
||||||
|
return isa<PartialApplyInst>(use->getUser());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasNonPartialApplyConsumingUse() const {
|
||||||
|
return llvm::any_of(consumingUsesNeedingCopy,
|
||||||
|
[](Operand *use) {
|
||||||
|
return !isa<PartialApplyInst>(use->getUser());
|
||||||
|
}) ||
|
||||||
|
llvm::any_of(finalConsumingUses, [](Operand *use) {
|
||||||
|
return !isa<PartialApplyInst>(use->getUser());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// MARK: Diagnostic Utilities
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
template <typename... T, typename... U>
|
template <typename... T, typename... U>
|
||||||
@@ -66,8 +149,179 @@ static StringRef getVariableNameForValue(MarkMustCheckInst *mmci) {
|
|||||||
return varName;
|
return varName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct DiagnosticEmitter {
|
||||||
|
SILFunction *fn;
|
||||||
|
const OSSACanonicalizer &canonicalizer;
|
||||||
|
SmallPtrSet<MarkMustCheckInst *, 4> valuesWithDiagnostics;
|
||||||
|
|
||||||
|
void emitCheckerDoesntUnderstandDiagnostic(MarkMustCheckInst *markedValue);
|
||||||
|
void emitGuaranteedDiagnostic(MarkMustCheckInst *markedValue);
|
||||||
|
void emitOwnedDiagnostic(MarkMustCheckInst *markedValue);
|
||||||
|
|
||||||
|
bool emittedAnyDiagnostics() const { return valuesWithDiagnostics.size(); }
|
||||||
|
|
||||||
|
bool emittedDiagnosticForValue(MarkMustCheckInst *markedValue) const {
|
||||||
|
return valuesWithDiagnostics.count(markedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Emit diagnostics for the final consuming uses and consuming uses needing
|
||||||
|
/// copy. If filter is non-null, allow for the caller to pre-process operands
|
||||||
|
/// and emit their own diagnostic. If filter returns true, then we assume that
|
||||||
|
/// the caller processed it correctly. false, then we continue to process it.
|
||||||
|
void emitDiagnosticsForFoundUses(bool ignorePartialApply = false) const;
|
||||||
|
void emitDiagnosticsForPartialApplyUses() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
void DiagnosticEmitter::emitCheckerDoesntUnderstandDiagnostic(
|
||||||
|
MarkMustCheckInst *markedValue) {
|
||||||
|
// If we failed to canonicalize ownership, there was something in the SIL
|
||||||
|
// that copy propagation did not understand. Emit a we did not understand
|
||||||
|
// error.
|
||||||
|
if (markedValue->getType().isMoveOnlyWrapped()) {
|
||||||
|
diagnose(fn->getASTContext(), markedValue->getLoc().getSourceLoc(),
|
||||||
|
diag::sil_moveonlychecker_not_understand_no_implicit_copy);
|
||||||
|
} else {
|
||||||
|
diagnose(fn->getASTContext(), markedValue->getLoc().getSourceLoc(),
|
||||||
|
diag::sil_moveonlychecker_not_understand_moveonly);
|
||||||
|
}
|
||||||
|
valuesWithDiagnostics.insert(markedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiagnosticEmitter::emitGuaranteedDiagnostic(
|
||||||
|
MarkMustCheckInst *markedValue) {
|
||||||
|
auto &astContext = fn->getASTContext();
|
||||||
|
StringRef varName = getVariableNameForValue(markedValue);
|
||||||
|
|
||||||
|
// See if we have any closure capture uses and emit a better diagnostic.
|
||||||
|
if (canonicalizer.hasPartialApplyConsumingUse()) {
|
||||||
|
diagnose(astContext,
|
||||||
|
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
|
||||||
|
diag::sil_moveonlychecker_guaranteed_value_captured_by_closure,
|
||||||
|
varName);
|
||||||
|
emitDiagnosticsForPartialApplyUses();
|
||||||
|
valuesWithDiagnostics.insert(markedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we do not have any non-partial apply consuming uses... just exit early.
|
||||||
|
if (!canonicalizer.hasNonPartialApplyConsumingUse())
|
||||||
|
return;
|
||||||
|
|
||||||
|
diagnose(astContext,
|
||||||
|
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
|
||||||
|
diag::sil_moveonlychecker_guaranteed_value_consumed, varName);
|
||||||
|
emitDiagnosticsForFoundUses(true /*ignore partial apply uses*/);
|
||||||
|
valuesWithDiagnostics.insert(markedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiagnosticEmitter::emitOwnedDiagnostic(MarkMustCheckInst *markedValue) {
|
||||||
|
auto &astContext = fn->getASTContext();
|
||||||
|
StringRef varName = getVariableNameForValue(markedValue);
|
||||||
|
|
||||||
|
diagnose(astContext,
|
||||||
|
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
|
||||||
|
diag::sil_moveonlychecker_owned_value_consumed_more_than_once,
|
||||||
|
varName);
|
||||||
|
|
||||||
|
emitDiagnosticsForFoundUses();
|
||||||
|
valuesWithDiagnostics.insert(markedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiagnosticEmitter::emitDiagnosticsForFoundUses(
|
||||||
|
bool ignorePartialApplyUses) const {
|
||||||
|
auto &astContext = fn->getASTContext();
|
||||||
|
|
||||||
|
for (auto *consumingUse : canonicalizer.consumingUsesNeedingCopy) {
|
||||||
|
// See if the consuming use is an owned moveonly_to_copyable whose only
|
||||||
|
// user is a return. In that case, use the return loc instead. We do this
|
||||||
|
// b/c it is illegal to put a return value location on a non-return value
|
||||||
|
// instruction... so we have to hack around this slightly.
|
||||||
|
auto *user = consumingUse->getUser();
|
||||||
|
auto loc = user->getLoc();
|
||||||
|
if (auto *mtc = dyn_cast<MoveOnlyWrapperToCopyableValueInst>(user)) {
|
||||||
|
if (auto *ri = mtc->getSingleUserOfType<ReturnInst>()) {
|
||||||
|
loc = ri->getLoc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignorePartialApplyUses &&
|
||||||
|
isa<PartialApplyInst>(consumingUse->getUser()))
|
||||||
|
continue;
|
||||||
|
diagnose(astContext, loc.getSourceLoc(),
|
||||||
|
diag::sil_moveonlychecker_consuming_use_here);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto *consumingUse : canonicalizer.finalConsumingUses) {
|
||||||
|
// See if the consuming use is an owned moveonly_to_copyable whose only
|
||||||
|
// user is a return. In that case, use the return loc instead. We do this
|
||||||
|
// b/c it is illegal to put a return value location on a non-return value
|
||||||
|
// instruction... so we have to hack around this slightly.
|
||||||
|
auto *user = consumingUse->getUser();
|
||||||
|
auto loc = user->getLoc();
|
||||||
|
if (auto *mtc = dyn_cast<MoveOnlyWrapperToCopyableValueInst>(user)) {
|
||||||
|
if (auto *ri = mtc->getSingleUserOfType<ReturnInst>()) {
|
||||||
|
loc = ri->getLoc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignorePartialApplyUses &&
|
||||||
|
isa<PartialApplyInst>(consumingUse->getUser()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
diagnose(astContext, loc.getSourceLoc(),
|
||||||
|
diag::sil_moveonlychecker_consuming_use_here);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiagnosticEmitter::emitDiagnosticsForPartialApplyUses() const {
|
||||||
|
auto &astContext = fn->getASTContext();
|
||||||
|
|
||||||
|
for (auto *consumingUse : canonicalizer.consumingUsesNeedingCopy) {
|
||||||
|
// See if the consuming use is an owned moveonly_to_copyable whose only
|
||||||
|
// user is a return. In that case, use the return loc instead. We do this
|
||||||
|
// b/c it is illegal to put a return value location on a non-return value
|
||||||
|
// instruction... so we have to hack around this slightly.
|
||||||
|
auto *user = consumingUse->getUser();
|
||||||
|
auto loc = user->getLoc();
|
||||||
|
if (auto *mtc = dyn_cast<MoveOnlyWrapperToCopyableValueInst>(user)) {
|
||||||
|
if (auto *ri = mtc->getSingleUserOfType<ReturnInst>()) {
|
||||||
|
loc = ri->getLoc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isa<PartialApplyInst>(consumingUse->getUser()))
|
||||||
|
continue;
|
||||||
|
diagnose(astContext, loc.getSourceLoc(),
|
||||||
|
diag::sil_moveonlychecker_consuming_closure_use_here);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto *consumingUse : canonicalizer.finalConsumingUses) {
|
||||||
|
// See if the consuming use is an owned moveonly_to_copyable whose only
|
||||||
|
// user is a return. In that case, use the return loc instead. We do this
|
||||||
|
// b/c it is illegal to put a return value location on a non-return value
|
||||||
|
// instruction... so we have to hack around this slightly.
|
||||||
|
auto *user = consumingUse->getUser();
|
||||||
|
auto loc = user->getLoc();
|
||||||
|
if (auto *mtc = dyn_cast<MoveOnlyWrapperToCopyableValueInst>(user)) {
|
||||||
|
if (auto *ri = mtc->getSingleUserOfType<ReturnInst>()) {
|
||||||
|
loc = ri->getLoc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isa<PartialApplyInst>(consumingUse->getUser()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
diagnose(astContext, loc.getSourceLoc(),
|
||||||
|
diag::sil_moveonlychecker_consuming_closure_use_here);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Main Pass
|
// MARK: Main Pass
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -78,14 +332,6 @@ struct MoveOnlyChecker {
|
|||||||
/// A set of mark_must_check that we are actually going to process.
|
/// A set of mark_must_check that we are actually going to process.
|
||||||
SmallSetVector<MarkMustCheckInst *, 32> moveIntroducersToProcess;
|
SmallSetVector<MarkMustCheckInst *, 32> moveIntroducersToProcess;
|
||||||
|
|
||||||
/// A per mark must check, vector of uses that copy propagation says need a
|
|
||||||
/// copy and thus are not final consuming uses.
|
|
||||||
SmallVector<Operand *, 32> consumingUsesNeedingCopy;
|
|
||||||
|
|
||||||
/// A per mark must check, vector of consuming uses that copy propagation says
|
|
||||||
/// are actual last uses.
|
|
||||||
SmallVector<Operand *, 32> finalConsumingUses;
|
|
||||||
|
|
||||||
MoveOnlyChecker(SILFunction *fn, DeadEndBlocks *deBlocks) : fn(fn) {}
|
MoveOnlyChecker(SILFunction *fn, DeadEndBlocks *deBlocks) : fn(fn) {}
|
||||||
|
|
||||||
/// Search through the current function for candidate mark_must_check
|
/// Search through the current function for candidate mark_must_check
|
||||||
@@ -97,10 +343,6 @@ struct MoveOnlyChecker {
|
|||||||
/// recognize after emitting the diagnostic.
|
/// recognize after emitting the diagnostic.
|
||||||
bool searchForCandidateMarkMustChecks();
|
bool searchForCandidateMarkMustChecks();
|
||||||
|
|
||||||
/// Emits an error diagnostic for \p markedValue.
|
|
||||||
void emitDiagnostic(MarkMustCheckInst *markedValue,
|
|
||||||
bool originalValueGuaranteed);
|
|
||||||
|
|
||||||
bool check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
|
bool check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
|
||||||
DominanceInfo *domTree);
|
DominanceInfo *domTree);
|
||||||
};
|
};
|
||||||
@@ -314,61 +556,6 @@ bool MoveOnlyChecker::searchForCandidateMarkMustChecks() {
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveOnlyChecker::emitDiagnostic(MarkMustCheckInst *markedValue,
|
|
||||||
bool originalValueGuaranteed) {
|
|
||||||
auto &astContext = fn->getASTContext();
|
|
||||||
StringRef varName = getVariableNameForValue(markedValue);
|
|
||||||
|
|
||||||
if (originalValueGuaranteed) {
|
|
||||||
diagnose(astContext,
|
|
||||||
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
|
|
||||||
diag::sil_moveonlychecker_guaranteed_value_consumed, varName);
|
|
||||||
} else {
|
|
||||||
diagnose(astContext,
|
|
||||||
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
|
|
||||||
diag::sil_moveonlychecker_owned_value_consumed_more_than_once,
|
|
||||||
varName);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (consumingUsesNeedingCopy.size()) {
|
|
||||||
auto *consumingUse = consumingUsesNeedingCopy.pop_back_val();
|
|
||||||
|
|
||||||
// See if the consuming use is an owned moveonly_to_copyable whose only
|
|
||||||
// user is a return. In that case, use the return loc instead. We do this
|
|
||||||
// b/c it is illegal to put a return value location on a non-return value
|
|
||||||
// instruction... so we have to hack around this slightly.
|
|
||||||
auto *user = consumingUse->getUser();
|
|
||||||
auto loc = user->getLoc();
|
|
||||||
if (auto *mtc = dyn_cast<MoveOnlyWrapperToCopyableValueInst>(user)) {
|
|
||||||
if (auto *ri = mtc->getSingleUserOfType<ReturnInst>()) {
|
|
||||||
loc = ri->getLoc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnose(astContext, loc.getSourceLoc(),
|
|
||||||
diag::sil_moveonlychecker_consuming_use_here);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (finalConsumingUses.size()) {
|
|
||||||
auto *consumingUse = finalConsumingUses.pop_back_val();
|
|
||||||
|
|
||||||
// See if the consuming use is an owned moveonly_to_copyable whose only
|
|
||||||
// user is a return. In that case, use the return loc instead. We do this
|
|
||||||
// b/c it is illegal to put a return value location on a non-return value
|
|
||||||
// instruction... so we have to hack around this slightly.
|
|
||||||
auto *user = consumingUse->getUser();
|
|
||||||
auto loc = user->getLoc();
|
|
||||||
if (auto *mtc = dyn_cast<MoveOnlyWrapperToCopyableValueInst>(user)) {
|
|
||||||
if (auto *ri = mtc->getSingleUserOfType<ReturnInst>()) {
|
|
||||||
loc = ri->getLoc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnose(astContext, loc.getSourceLoc(),
|
|
||||||
diag::sil_moveonlychecker_consuming_use_here);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
|
bool MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
|
||||||
DominanceInfo *domTree) {
|
DominanceInfo *domTree) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
@@ -392,44 +579,21 @@ bool MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
|
|||||||
instToDelete->eraseFromParent();
|
instToDelete->eraseFromParent();
|
||||||
});
|
});
|
||||||
InstructionDeleter deleter(std::move(callbacks));
|
InstructionDeleter deleter(std::move(callbacks));
|
||||||
|
OSSACanonicalizer canonicalizer(fn, accessBlockAnalysis, domTree, deleter);
|
||||||
|
DiagnosticEmitter diagnosticEmitter{fn, canonicalizer, {}};
|
||||||
|
|
||||||
auto foundConsumingUseNeedingCopy = [&](Operand *use) {
|
|
||||||
consumingUsesNeedingCopy.push_back(use);
|
|
||||||
};
|
|
||||||
auto foundConsumingUseNotNeedingCopy = [&](Operand *use) {
|
|
||||||
finalConsumingUses.push_back(use);
|
|
||||||
};
|
|
||||||
|
|
||||||
CanonicalizeOSSALifetime canonicalizer(
|
|
||||||
false /*pruneDebugMode*/, !fn->shouldOptimize() /*maximizeLifetime*/,
|
|
||||||
accessBlockAnalysis, domTree, deleter, foundConsumingUseNeedingCopy,
|
|
||||||
foundConsumingUseNotNeedingCopy);
|
|
||||||
auto moveIntroducers = llvm::makeArrayRef(moveIntroducersToProcess.begin(),
|
auto moveIntroducers = llvm::makeArrayRef(moveIntroducersToProcess.begin(),
|
||||||
moveIntroducersToProcess.end());
|
moveIntroducersToProcess.end());
|
||||||
SmallPtrSet<MarkMustCheckInst *, 4> valuesWithDiagnostics;
|
|
||||||
while (!moveIntroducers.empty()) {
|
while (!moveIntroducers.empty()) {
|
||||||
SWIFT_DEFER {
|
SWIFT_DEFER { canonicalizer.clear(); };
|
||||||
consumingUsesNeedingCopy.clear();
|
|
||||||
finalConsumingUses.clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
MarkMustCheckInst *markedValue = moveIntroducers.front();
|
MarkMustCheckInst *markedValue = moveIntroducers.front();
|
||||||
moveIntroducers = moveIntroducers.drop_front(1);
|
moveIntroducers = moveIntroducers.drop_front(1);
|
||||||
LLVM_DEBUG(llvm::dbgs() << "Visiting: " << *markedValue);
|
LLVM_DEBUG(llvm::dbgs() << "Visiting: " << *markedValue);
|
||||||
|
|
||||||
// First canonicalize ownership.
|
// First canonicalize ownership.
|
||||||
if (!canonicalizer.canonicalizeValueLifetime(markedValue)) {
|
if (!canonicalizer.canonicalize(markedValue)) {
|
||||||
// If we failed to canonicalize ownership, there was something in the SIL
|
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic(markedValue);
|
||||||
// that copy propagation did not understand. Emit a we did not understand
|
|
||||||
// error.
|
|
||||||
if (markedValue->getType().isMoveOnlyWrapped()) {
|
|
||||||
diagnose(fn->getASTContext(), markedValue->getLoc().getSourceLoc(),
|
|
||||||
diag::sil_moveonlychecker_not_understand_no_implicit_copy);
|
|
||||||
} else {
|
|
||||||
diagnose(fn->getASTContext(), markedValue->getLoc().getSourceLoc(),
|
|
||||||
diag::sil_moveonlychecker_not_understand_moveonly);
|
|
||||||
}
|
|
||||||
valuesWithDiagnostics.insert(markedValue);
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
// Always set changed to true if we succeeded in canonicalizing since we
|
// Always set changed to true if we succeeded in canonicalizing since we
|
||||||
@@ -440,14 +604,13 @@ bool MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
|
|||||||
// If we are asked to perform guaranteed checking, emit an error if we have
|
// If we are asked to perform guaranteed checking, emit an error if we have
|
||||||
// /any/ consuming uses.
|
// /any/ consuming uses.
|
||||||
if (markedValue->getCheckKind() == MarkMustCheckInst::CheckKind::NoCopy) {
|
if (markedValue->getCheckKind() == MarkMustCheckInst::CheckKind::NoCopy) {
|
||||||
if (!consumingUsesNeedingCopy.empty() || !finalConsumingUses.empty()) {
|
if (canonicalizer.foundAnyConsumingUses()) {
|
||||||
emitDiagnostic(markedValue, true /*original value guaranteed*/);
|
diagnosticEmitter.emitGuaranteedDiagnostic(markedValue);
|
||||||
valuesWithDiagnostics.insert(markedValue);
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (consumingUsesNeedingCopy.empty()) {
|
if (!canonicalizer.foundConsumingUseRequiringCopy()) {
|
||||||
// If we failed to understand how to perform the check or did not find
|
// If we failed to understand how to perform the check or did not find
|
||||||
// any targets... continue. In the former case we want to fail with a
|
// any targets... continue. In the former case we want to fail with a
|
||||||
// checker did not understand diagnostic later and in the former, we
|
// checker did not understand diagnostic later and in the former, we
|
||||||
@@ -455,10 +618,10 @@ bool MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
emitDiagnostic(markedValue, false /*original value guaranteed*/);
|
diagnosticEmitter.emitOwnedDiagnostic(markedValue);
|
||||||
valuesWithDiagnostics.insert(markedValue);
|
|
||||||
}
|
}
|
||||||
bool emittedDiagnostic = valuesWithDiagnostics.size();
|
|
||||||
|
bool emittedDiagnostic = diagnosticEmitter.emittedAnyDiagnostics();
|
||||||
|
|
||||||
// Ok, we have success. All of our marker instructions were proven as safe or
|
// Ok, we have success. All of our marker instructions were proven as safe or
|
||||||
// we emitted a diagnostic. Now we need to clean up the IR by eliminating our
|
// we emitted a diagnostic. Now we need to clean up the IR by eliminating our
|
||||||
@@ -477,7 +640,7 @@ bool MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
|
|||||||
|
|
||||||
// If we didn't emit a diagnostic on a non-trivial guaranteed argument,
|
// If we didn't emit a diagnostic on a non-trivial guaranteed argument,
|
||||||
// eliminate the copy_value, destroy_values, and the mark_must_check.
|
// eliminate the copy_value, destroy_values, and the mark_must_check.
|
||||||
if (!valuesWithDiagnostics.count(markedInst)) {
|
if (!diagnosticEmitter.emittedDiagnosticForValue(markedInst)) {
|
||||||
if (markedInst->getCheckKind() == MarkMustCheckInst::CheckKind::NoCopy) {
|
if (markedInst->getCheckKind() == MarkMustCheckInst::CheckKind::NoCopy) {
|
||||||
if (auto *cvi = dyn_cast<CopyValueInst>(markedInst->getOperand())) {
|
if (auto *cvi = dyn_cast<CopyValueInst>(markedInst->getOperand())) {
|
||||||
if (auto *arg = dyn_cast<SILFunctionArgument>(cvi->getOperand())) {
|
if (auto *arg = dyn_cast<SILFunctionArgument>(cvi->getOperand())) {
|
||||||
|
|||||||
@@ -845,3 +845,22 @@ func closeOverStructDontCopyTrivial() {
|
|||||||
a = StructWithMutatingMethod()
|
a = StructWithMutatingMethod()
|
||||||
takeClosure { a.x }
|
takeClosure { a.x }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure that we handle closure argument initialization when due to forward
|
||||||
|
// declaration we represent a let as an lvalue
|
||||||
|
func test() {
|
||||||
|
let k: SomeClass
|
||||||
|
let k2: SomeClass
|
||||||
|
var boolean: Bool { true }
|
||||||
|
|
||||||
|
if boolean {
|
||||||
|
k = SomeClass()
|
||||||
|
k2 = SomeClass()
|
||||||
|
} else {
|
||||||
|
k = SomeClass()
|
||||||
|
k2 = SomeClass()
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(k.x == k2.x)
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2046,9 +2046,12 @@ public func enumPatternMatchSwitch2WhereClause2OwnedArg(_ x2: __owned EnumTy) {
|
|||||||
// Closure and Defer Tests //
|
// Closure and Defer Tests //
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
|
||||||
public func closureClassUseAfterConsume1(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureClassUseAfterConsume1(_ x: Klass) {
|
||||||
let f = { // expected-note {{consuming use}}
|
// expected-error @-1 {{'x' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
|
let f = { // expected-note {{closure capture}}
|
||||||
let x2 = x // expected-error {{'x2' consumed more than once}}
|
let x2 = x // expected-error {{'x2' consumed more than once}}
|
||||||
|
// expected-note @-1 {{consuming use}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2) // expected-note {{consuming use}}
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2) // expected-note {{consuming use}}
|
print(x2) // expected-note {{consuming use}}
|
||||||
@@ -2079,50 +2082,58 @@ public func closureClassUseAfterConsumeArg(_ argX: Klass) {
|
|||||||
|
|
||||||
public func closureCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-note {{consuming use}}
|
let x2 = x // expected-note {{consuming use}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = {
|
let f = {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureCaptureClassUseAfterConsumeError(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureCaptureClassUseAfterConsumeError(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-error {{'x2' consumed more than once}}
|
let x2 = x
|
||||||
// expected-note @-1 {{consuming use}}
|
// expected-error @-1 {{'x2' consumed more than once}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-note @-3 {{consuming use}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
let x3 = x2 // expected-note {{consuming use}}
|
let x3 = x2 // expected-note {{consuming use}}
|
||||||
let _ = x3
|
let _ = x3
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureCaptureClassArgUseAfterConsume(_ x2: Klass) { // expected-error {{'x2' has guaranteed ownership but was consumed}}
|
public func closureCaptureClassArgUseAfterConsume(_ x2: Klass) {
|
||||||
let f = { // expected-note {{consuming use}}
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
|
let f = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
|
public func closureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = {
|
let f = {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) { // expected-error {{'x2' consumed more than once}}
|
public func closureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) {
|
||||||
|
// expected-error @-1 {{'x2' consumed more than once}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
let x3 = x2 // expected-note {{consuming use}}
|
let x3 = x2 // expected-note {{consuming use}}
|
||||||
@@ -2131,63 +2142,68 @@ public func closureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) { /
|
|||||||
|
|
||||||
public func deferCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func deferCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-note {{consuming use}}
|
let x2 = x // expected-note {{consuming use}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print(x) // expected-note {{consuming use}}
|
print(x) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deferCaptureClassUseAfterConsume2(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func deferCaptureClassUseAfterConsume2(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-error {{'x2' consumed more than once}}
|
let x2 = x // expected-error {{'x2' consumed more than once}}
|
||||||
// expected-note @-1 {{consuming use}}
|
// expected-note @-1 {{consuming use}}
|
||||||
// TODO: Defer error is b/c we have to lifetime extend x2 for the defer. The
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
// use is a guaranteed use, so we don't emit an error on that use.
|
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
let x3 = x2 // expected-note {{consuming use}}
|
let x3 = x2 // expected-note {{consuming use}}
|
||||||
let _ = x3
|
let _ = x3
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deferCaptureClassArgUseAfterConsume(_ x2: Klass) {
|
public func deferCaptureClassArgUseAfterConsume(_ x2: Klass) {
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
|
public func deferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) { // expected-error {{'x2' consumed more than once}}
|
public func deferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) {
|
||||||
|
// expected-error @-1 {{'x2' consumed more than once}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print(x2) // expected-note {{consuming use}}
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndDeferCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureAndDeferCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-note {{consuming use}}
|
let x2 = x // expected-note {{consuming use}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = {
|
let f = {
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -2196,12 +2212,14 @@ public func closureAndDeferCaptureClassUseAfterConsume(_ x: Klass) { // expected
|
|||||||
|
|
||||||
public func closureAndDeferCaptureClassUseAfterConsume2(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureAndDeferCaptureClassUseAfterConsume2(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-note {{consuming use}}
|
let x2 = x // expected-note {{consuming use}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = {
|
let f = {
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -2210,13 +2228,15 @@ public func closureAndDeferCaptureClassUseAfterConsume2(_ x: Klass) { // expecte
|
|||||||
|
|
||||||
public func closureAndDeferCaptureClassUseAfterConsume3(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureAndDeferCaptureClassUseAfterConsume3(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-error {{'x2' consumed more than once}}
|
let x2 = x // expected-error {{'x2' consumed more than once}}
|
||||||
// expected-note @-1 {{consuming use}}
|
// expected-note @-1 {{consuming use}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -2224,12 +2244,14 @@ public func closureAndDeferCaptureClassUseAfterConsume3(_ x: Klass) { // expecte
|
|||||||
classConsume(x2) // expected-note {{consuming use}}
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: Klass) { // expected-error {{'x2' has guaranteed ownership but was consumed}}
|
public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: Klass) {
|
||||||
let f = { // expected-note {{consuming use}}
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
|
let f = { // expected-note {{closure capture}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -2237,23 +2259,26 @@ public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: Klass) { // expe
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
|
public func closureAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = {
|
let f = {
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) { // expected-error {{'x2' consumed more than once}}
|
public func closureAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) {
|
||||||
|
// expected-error @-1 {{'x2' consumed more than once}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -2263,11 +2288,13 @@ public func closureAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Kl
|
|||||||
|
|
||||||
public func closureAndClosureCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureAndClosureCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-note {{consuming use}}
|
let x2 = x // expected-note {{consuming use}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
let f = {
|
let f = {
|
||||||
let g = {
|
let g = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
g()
|
g()
|
||||||
}
|
}
|
||||||
@@ -2276,12 +2303,14 @@ public func closureAndClosureCaptureClassUseAfterConsume(_ x: Klass) { // expect
|
|||||||
|
|
||||||
public func closureAndClosureCaptureClassUseAfterConsume2(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureAndClosureCaptureClassUseAfterConsume2(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-error {{'x2' consumed more than once}}
|
let x2 = x // expected-error {{'x2' consumed more than once}}
|
||||||
// expected-note @-1 {{consuming use}}
|
// expected-note @-1 {{consuming use}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
let g = {
|
let g = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
g()
|
g()
|
||||||
}
|
}
|
||||||
@@ -2290,12 +2319,15 @@ public func closureAndClosureCaptureClassUseAfterConsume2(_ x: Klass) { // expec
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: Klass) { // expected-error {{'x2' has guaranteed ownership but was consumed}}
|
public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: Klass) {
|
||||||
let f = { // expected-note {{consuming use}}
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let g = {
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
|
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
|
let f = { // expected-note {{closure capture}}
|
||||||
|
let g = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
g()
|
g()
|
||||||
}
|
}
|
||||||
@@ -2303,23 +2335,28 @@ public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: Klass) { // ex
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
|
public func closureAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
let f = {
|
let f = {
|
||||||
let g = {
|
let g = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
g()
|
g()
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) { // expected-error {{'x2' consumed more than once}}
|
public func closureAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) {
|
||||||
|
// expected-error @-1 {{'x2' consumed more than once}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
let g = {
|
let g = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
g()
|
g()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1342,9 +1342,12 @@ public func enumPatternMatchSwitch2WhereClause2OwnedArg(_ x2: __owned EnumTy) {
|
|||||||
// Closure and Defer Tests //
|
// Closure and Defer Tests //
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
|
||||||
public func closureClassUseAfterConsume1(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureClassUseAfterConsume1(_ x: NonTrivialStruct) {
|
||||||
let f = { // expected-note {{consuming use}}
|
// expected-error @-1 {{'x' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
|
let f = { // expected-note {{closure capture}}
|
||||||
let x2 = x // expected-error {{'x2' consumed more than once}}
|
let x2 = x // expected-error {{'x2' consumed more than once}}
|
||||||
|
// expected-note @-1 {{consuming use}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2) // expected-note {{consuming use}}
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2) // expected-note {{consuming use}}
|
print(x2) // expected-note {{consuming use}}
|
||||||
@@ -1375,50 +1378,57 @@ public func closureClassUseAfterConsumeArg(_ argX: NonTrivialStruct) {
|
|||||||
|
|
||||||
public func closureCaptureClassUseAfterConsume(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureCaptureClassUseAfterConsume(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-note {{consuming use}}
|
let x2 = x // expected-note {{consuming use}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = {
|
let f = {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureCaptureClassUseAfterConsumeError(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureCaptureClassUseAfterConsumeError(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-error {{'x2' consumed more than once}}
|
let x2 = x // expected-error {{'x2' consumed more than once}}
|
||||||
// expected-note @-1 {{consuming use}}
|
// expected-note @-1 {{consuming use}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
let x3 = x2 // expected-note {{consuming use}}
|
let x3 = x2 // expected-note {{consuming use}}
|
||||||
let _ = x3
|
let _ = x3
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureCaptureClassArgUseAfterConsume(_ x2: NonTrivialStruct) { // expected-error {{'x2' has guaranteed ownership but was consumed}}
|
public func closureCaptureClassArgUseAfterConsume(_ x2: NonTrivialStruct) {
|
||||||
let f = { // expected-note {{consuming use}}
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
|
let f = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) {
|
public func closureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) {
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = {
|
let f = {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned NonTrivialStruct) { // expected-error {{'x2' consumed more than once}}
|
public func closureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned NonTrivialStruct) {
|
||||||
|
// expected-error @-1 {{'x2' consumed more than once}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
let x3 = x2 // expected-note {{consuming use}}
|
let x3 = x2 // expected-note {{consuming use}}
|
||||||
@@ -1427,63 +1437,71 @@ public func closureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned NonTrivial
|
|||||||
|
|
||||||
public func deferCaptureClassUseAfterConsume(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func deferCaptureClassUseAfterConsume(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-note {{consuming use}}
|
let x2 = x // expected-note {{consuming use}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print(x) // expected-note {{consuming use}}
|
print(x) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deferCaptureClassUseAfterConsume2(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func deferCaptureClassUseAfterConsume2(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-error {{'x2' consumed more than once}}
|
let x2 = x // expected-error {{'x2' consumed more than once}}
|
||||||
// expected-note @-1 {{consuming use}}
|
// expected-note @-1 {{consuming use}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
// TODO: Defer error is b/c we have to lifetime extend x2 for the defer. The
|
// TODO: Defer error is b/c we have to lifetime extend x2 for the defer. The
|
||||||
// use is a guaranteed use, so we don't emit an error on that use.
|
// use is a guaranteed use, so we don't emit an error on that use.
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
let x3 = x2 // expected-note {{consuming use}}
|
let x3 = x2 // expected-note {{consuming use}}
|
||||||
let _ = x3
|
let _ = x3
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deferCaptureClassArgUseAfterConsume(_ x2: NonTrivialStruct) {
|
public func deferCaptureClassArgUseAfterConsume(_ x2: NonTrivialStruct) {
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) {
|
public func deferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) {
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned NonTrivialStruct) { // expected-error {{'x2' consumed more than once}}
|
public func deferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned NonTrivialStruct) {
|
||||||
|
// expected-error @-1 {{'x2' consumed more than once}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print(x2) // expected-note {{consuming use}}
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndDeferCaptureClassUseAfterConsume(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureAndDeferCaptureClassUseAfterConsume(_ x: NonTrivialStruct) {
|
||||||
|
// expected-error @-1 {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-note {{consuming use}}
|
let x2 = x // expected-note {{consuming use}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = {
|
let f = {
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -1492,12 +1510,14 @@ public func closureAndDeferCaptureClassUseAfterConsume(_ x: NonTrivialStruct) {
|
|||||||
|
|
||||||
public func closureAndDeferCaptureClassUseAfterConsume2(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureAndDeferCaptureClassUseAfterConsume2(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-note {{consuming use}}
|
let x2 = x // expected-note {{consuming use}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = {
|
let f = {
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -1506,13 +1526,15 @@ public func closureAndDeferCaptureClassUseAfterConsume2(_ x: NonTrivialStruct) {
|
|||||||
|
|
||||||
public func closureAndDeferCaptureClassUseAfterConsume3(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureAndDeferCaptureClassUseAfterConsume3(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-error {{'x2' consumed more than once}}
|
let x2 = x // expected-error {{'x2' consumed more than once}}
|
||||||
// expected-note @-1 {{consuming use}}
|
// expected-note @-1 {{consuming use}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -1521,11 +1543,12 @@ public func closureAndDeferCaptureClassUseAfterConsume3(_ x: NonTrivialStruct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: NonTrivialStruct) { // expected-error {{'x2' has guaranteed ownership but was consumed}}
|
public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: NonTrivialStruct) { // expected-error {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = { // expected-note {{consuming use}}
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
|
let f = { // expected-note {{closure capture}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -1533,11 +1556,12 @@ public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: NonTrivialStruct
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) {
|
public func closureAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) {
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = {
|
let f = {
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -1545,11 +1569,12 @@ public func closureAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Non
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned NonTrivialStruct) { // expected-error {{'x2' consumed more than once}}
|
public func closureAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned NonTrivialStruct) { // expected-error {{'x2' consumed more than once}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
defer {
|
defer {
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
print("foo")
|
print("foo")
|
||||||
}
|
}
|
||||||
@@ -1559,11 +1584,13 @@ public func closureAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned No
|
|||||||
|
|
||||||
public func closureAndClosureCaptureClassUseAfterConsume(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureAndClosureCaptureClassUseAfterConsume(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-note {{consuming use}}
|
let x2 = x // expected-note {{consuming use}}
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
let f = {
|
let f = {
|
||||||
let g = {
|
let g = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
g()
|
g()
|
||||||
}
|
}
|
||||||
@@ -1573,11 +1600,13 @@ public func closureAndClosureCaptureClassUseAfterConsume(_ x: NonTrivialStruct)
|
|||||||
public func closureAndClosureCaptureClassUseAfterConsume2(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
public func closureAndClosureCaptureClassUseAfterConsume2(_ x: NonTrivialStruct) { // expected-error {{'x' has guaranteed ownership but was consumed}}
|
||||||
let x2 = x // expected-error {{'x2' consumed more than once}}
|
let x2 = x // expected-error {{'x2' consumed more than once}}
|
||||||
// expected-note @-1 {{consuming use}}
|
// expected-note @-1 {{consuming use}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
let g = {
|
let g = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
g()
|
g()
|
||||||
}
|
}
|
||||||
@@ -1586,12 +1615,15 @@ public func closureAndClosureCaptureClassUseAfterConsume2(_ x: NonTrivialStruct)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: NonTrivialStruct) { // expected-error {{'x2' has guaranteed ownership but was consumed}}
|
public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: NonTrivialStruct) {
|
||||||
let f = { // expected-note {{consuming use}}
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
let g = {
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
|
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
|
let f = { // expected-note {{closure capture}}
|
||||||
|
let g = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
g()
|
g()
|
||||||
}
|
}
|
||||||
@@ -1599,23 +1631,28 @@ public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: NonTrivialStru
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) {
|
public func closureAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) {
|
||||||
|
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
let f = {
|
let f = {
|
||||||
let g = {
|
let g = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
g()
|
g()
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func closureAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned NonTrivialStruct) { // expected-error {{'x2' consumed more than once}}
|
public func closureAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned NonTrivialStruct) {
|
||||||
|
// expected-error @-1 {{'x2' consumed more than once}}
|
||||||
|
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
|
||||||
|
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
|
||||||
let f = { // expected-note {{consuming use}}
|
let f = { // expected-note {{consuming use}}
|
||||||
let g = {
|
let g = { // expected-note {{closure capture}}
|
||||||
classUseMoveOnlyWithoutEscaping(x2)
|
classUseMoveOnlyWithoutEscaping(x2)
|
||||||
classConsume(x2)
|
classConsume(x2) // expected-note {{consuming use}}
|
||||||
print(x2)
|
print(x2) // expected-note {{consuming use}}
|
||||||
}
|
}
|
||||||
g()
|
g()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user