Skip to content

Commit 36e14c7

Browse files
authored
Merge pull request #77160 from atrick/moveonly_markdep
Add move-only checker support for dependencies
2 parents 3ab2314 + fc9d0b3 commit 36e14c7

File tree

6 files changed

+83
-7
lines changed

6 files changed

+83
-7
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,6 +1650,21 @@ inline bool isAccessStorageIdentityCast(SingleValueInstruction *svi) {
16501650
}
16511651
}
16521652

1653+
// Strip access markers and casts that preserve the address type.
1654+
//
1655+
// Consider using RelativeAccessStorageWithBase::compute().
1656+
inline SILValue stripAccessAndIdentityCasts(SILValue v) {
1657+
if (auto *bai = dyn_cast<BeginAccessInst>(v)) {
1658+
return stripAccessAndIdentityCasts(bai->getOperand());
1659+
}
1660+
if (auto *svi = dyn_cast<SingleValueInstruction>(v)) {
1661+
if (isAccessStorageIdentityCast(svi)) {
1662+
return stripAccessAndIdentityCasts(svi->getAllOperands()[0].get());
1663+
}
1664+
}
1665+
return v;
1666+
}
1667+
16531668
/// An address, pointer, or box cast that occurs outside of the formal
16541669
/// access. These convert the base of accessed storage without affecting the
16551670
/// AccessPath. Useful for both use-def and def-use traversal. The source

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2379,7 +2379,7 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
23792379
if (moveChecker.canonicalizer.foundAnyConsumingUses()) {
23802380
LLVM_DEBUG(llvm::dbgs()
23812381
<< "Found mark must check [nocopy] error: " << *user);
2382-
auto operand = stripAccessMarkers(markedValue->getOperand());
2382+
auto operand = stripAccessAndIdentityCasts(markedValue->getOperand());
23832383
auto *fArg = dyn_cast<SILFunctionArgument>(operand);
23842384
auto *ptrToAddr = dyn_cast<PointerToAddressInst>(operand);
23852385

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureUtils.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,6 +1540,12 @@ static bool gatherBorrows(SILValue rootValue,
15401540
// escape. Is it legal to canonicalize ForwardingUnowned?
15411541
case OperandOwnership::ForwardingUnowned:
15421542
case OperandOwnership::PointerEscape:
1543+
if (auto *md = dyn_cast<MarkDependenceInst>(use->getUser())) {
1544+
// mark_depenence uses only keep its base value alive; they do not use
1545+
// the base value itself and are irrelevant for destructuring.
1546+
if (use == &md->getOperandRef(MarkDependenceInst::Base))
1547+
continue;
1548+
}
15431549
return false;
15441550

15451551
case OperandOwnership::InstantaneousUse:

lib/SILOptimizer/Mandatory/MoveOnlyObjectCheckerUtils.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,12 @@ bool MoveOnlyObjectCheckerPImpl::checkForSameInstMultipleUseErrors(
219219
case OperandOwnership::NonUse:
220220
continue;
221221

222-
// Conservatively treat a conversion to an unowned value as a pointer
223-
// escape. If we see this in the SIL, fail and return false so we emit a
224-
// "compiler doesn't understand error".
225222
case OperandOwnership::ForwardingUnowned:
226223
case OperandOwnership::PointerEscape:
227224
case OperandOwnership::BitwiseEscape:
228-
LLVM_DEBUG(llvm::dbgs()
229-
<< " Found forwarding unowned or escape!\n");
230-
return false;
225+
// None of the "unowned" uses can consume the original value. Simply
226+
// ignore them.
227+
continue;
231228

232229
case OperandOwnership::TrivialUse:
233230
case OperandOwnership::InstantaneousUse:

lib/SILOptimizer/Utils/VariableNameUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ SILValue VariableNameInferrer::findDebugInfoProvidingValueHelper(
642642
isa<ProjectBoxInst>(searchValue) || isa<CopyValueInst>(searchValue) ||
643643
isa<ConvertFunctionInst>(searchValue) ||
644644
isa<MarkUninitializedInst>(searchValue) ||
645+
isa<MarkDependenceInst>(searchValue) ||
645646
isa<CopyableToMoveOnlyWrapperAddrInst>(searchValue) ||
646647
isa<MoveOnlyWrapperToCopyableAddrInst>(searchValue) ||
647648
isa<MoveOnlyWrapperToCopyableValueInst>(searchValue) ||
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// RUN: %target-sil-opt -sil-move-only-address-checker -enable-sil-verify-all -verify %s | %FileCheck %s
2+
3+
// Verify move-only diagnostics on unsafe addressors.
4+
//
5+
// Note: .sil tests cannot easily recover variable names, so we see 'unknown' variables.
6+
7+
sil_stage raw
8+
9+
import Builtin
10+
import Swift
11+
import SwiftShims
12+
13+
class C {
14+
deinit
15+
init()
16+
}
17+
18+
struct NC : ~Copyable {
19+
@_hasStorage @_hasInitialValue var c: C { get set }
20+
deinit
21+
init()
22+
init(c: C = C())
23+
}
24+
25+
struct SNC : ~Copyable {
26+
var data: NC { get }
27+
var mutableData: NC { get set }
28+
init()
29+
}
30+
31+
sil @unsafeAddressor : $@convention(method) (@guaranteed SNC) -> UnsafePointer<NC>
32+
33+
sil @consumeNC : $@convention(thin) (@owned NC) -> ()
34+
35+
// CHECK-LABEL: sil hidden [ossa] @test_read_borrow : $@convention(thin) (@inout SNC) -> () {
36+
sil hidden [ossa] @test_read_borrow : $@convention(thin) (@inout SNC) -> () {
37+
bb0(%0 : $*SNC):
38+
debug_value %0 : $*SNC, var, name "snc", argno 1, expr op_deref
39+
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %0 : $*SNC
40+
%3 = begin_access [read] [static] %2 : $*SNC
41+
%4 = load_borrow [unchecked] %3 : $*SNC
42+
%5 = function_ref @unsafeAddressor : $@convention(method) (@guaranteed SNC) -> UnsafePointer<NC>
43+
%6 = apply %5(%4) : $@convention(method) (@guaranteed SNC) -> UnsafePointer<NC>
44+
%7 = struct_extract %6 : $UnsafePointer<NC>, #UnsafePointer._rawValue
45+
%8 = pointer_to_address %7 : $Builtin.RawPointer to [strict] $*NC
46+
%9 = mark_dependence [unresolved] %8 : $*NC on %3 : $*SNC
47+
%10 = begin_access [read] [unsafe] %9 : $*NC
48+
%11 = mark_unresolved_non_copyable_value [no_consume_or_assign] %10 : $*NC // expected-error {{'unknown' is borrowed and cannot be consumed}}
49+
%12 = load [copy] %11 : $*NC
50+
end_access %10 : $*NC
51+
end_borrow %4 : $SNC
52+
end_access %3 : $*SNC
53+
%16 = function_ref @consumeNC : $@convention(thin) (@owned NC) -> ()
54+
%17 = apply %16(%12) : $@convention(thin) (@owned NC) -> () // expected-note {{consumed here}}
55+
%18 = tuple ()
56+
return %18 : $()
57+
}

0 commit comments

Comments
 (0)