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:
Michael Gottesman
2022-12-14 13:51:28 -08:00
committed by GitHub
8 changed files with 535 additions and 250 deletions

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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())) {

View File

@@ -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)
}

View File

@@ -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()
} }

View File

@@ -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()
} }