@@ -2079,12 +2079,98 @@ bool ConsumeOperatorCopyableAddressesChecker::performClosureDataflow(
2079
2079
closureConsumes);
2080
2080
}
2081
2081
2082
+ struct MoveConstraint {
2083
+ enum Value : uint8_t {
2084
+ None,
2085
+ RequiresReinit,
2086
+ Illegal,
2087
+ } value;
2088
+
2089
+ operator Value () { return value; }
2090
+ MoveConstraint (Value value) : value(value) {}
2091
+
2092
+ static MoveConstraint forGuaranteed (bool guaranteed) {
2093
+ return guaranteed ? Illegal : None;
2094
+ }
2095
+
2096
+ bool isIllegal () { return value == Illegal; }
2097
+ };
2098
+
2099
+ static MoveConstraint getMoveConstraint (SILValue addr) {
2100
+ assert (addr->getType ().isAddress ());
2101
+ auto access = AccessPathWithBase::computeInScope (addr);
2102
+ auto base = access.getAccessBase ();
2103
+ switch (access.accessPath .getStorage ().getKind ()) {
2104
+ case AccessRepresentation::Kind::Box:
2105
+ // Even if the box is guaranteed, it may be permitted to consume its
2106
+ // storage.
2107
+ return MoveConstraint::None;
2108
+ case AccessRepresentation::Kind::Stack: {
2109
+ // An alloc_stack is guaranteed if it's a "store_borrow destination".
2110
+ auto *asi = cast<AllocStackInst>(base.getBaseAddress ());
2111
+ return MoveConstraint::forGuaranteed (
2112
+ !asi->getUsersOfType <StoreBorrowInst>().empty ());
2113
+ }
2114
+ case AccessRepresentation::Kind::Global:
2115
+ // A global can be consumed if it's reinitialized.
2116
+ return MoveConstraint::RequiresReinit;
2117
+ case AccessRepresentation::Kind::Class:
2118
+ // A class field can be consumed if it's reinitialized.
2119
+ return MoveConstraint::RequiresReinit;
2120
+ case AccessRepresentation::Kind::Tail:
2121
+ // A class field can be consumed if it's reinitialized.
2122
+ return MoveConstraint::RequiresReinit;
2123
+ case AccessRepresentation::Kind::Argument: {
2124
+ // An indirect argument is guaranteed if it's @in_guaranteed.
2125
+ auto *arg = base.getArgument ();
2126
+ return MoveConstraint::forGuaranteed (
2127
+ arg->getArgumentConvention ().isGuaranteedConvention ());
2128
+ }
2129
+ case AccessRepresentation::Kind::Yield: {
2130
+ auto baseAddr = base.getBaseAddress ();
2131
+ auto *bai = cast<BeginApplyInst>(
2132
+ cast<MultipleValueInstructionResult>(baseAddr)->getParent ());
2133
+ auto index = *bai->getIndexOfResult (baseAddr);
2134
+ auto info = bai->getSubstCalleeConv ().getYieldInfoForOperandIndex (index);
2135
+ return MoveConstraint::forGuaranteed (!info.isConsumed ());
2136
+ }
2137
+ case AccessRepresentation::Kind::Nested: {
2138
+ auto *bai = cast<BeginAccessInst>(base.getBaseAddress ());
2139
+ if (bai->getAccessKind () == SILAccessKind::Init ||
2140
+ bai->getAccessKind () == SILAccessKind::Read)
2141
+ return MoveConstraint::Illegal;
2142
+ // Allow moves from both modify and deinit.
2143
+ return MoveConstraint::None;
2144
+ }
2145
+ case AccessRepresentation::Kind::Unidentified:
2146
+ // Conservatively reject for now.
2147
+ return MoveConstraint::Illegal;
2148
+ }
2149
+ }
2150
+
2082
2151
// Returns true if we emitted a diagnostic and handled the single block
2083
2152
// case. Returns false if we visited all of the uses and seeded the UseState
2084
2153
// struct with the information needed to perform our interprocedural dataflow.
2085
2154
bool ConsumeOperatorCopyableAddressesChecker::performSingleBasicBlockAnalysis (
2086
2155
SILValue address, DebugVarCarryingInst addressDebugInst,
2087
2156
MarkUnresolvedMoveAddrInst *mvi) {
2157
+ if (getMoveConstraint (mvi->getSrc ()).isIllegal ()) {
2158
+ auto &astCtx = mvi->getFunction ()->getASTContext ();
2159
+ StringRef name = getDebugVarName (address);
2160
+ diagnose (astCtx, getSourceLocFromValue (address),
2161
+ diag::sil_movechecking_guaranteed_value_consumed, name);
2162
+ diagnose (astCtx, mvi->getLoc ().getSourceLoc (),
2163
+ diag::sil_movechecking_consuming_use_here);
2164
+
2165
+ // Replace the marker instruction with a copy_addr to avoid subsequent
2166
+ // diagnostics.
2167
+ SILBuilderWithScope builder (mvi);
2168
+ builder.createCopyAddr (mvi->getLoc (), mvi->getSrc (), mvi->getDest (),
2169
+ IsNotTake, IsInitialization);
2170
+ mvi->eraseFromParent ();
2171
+
2172
+ return true ;
2173
+ }
2088
2174
// First scan downwards to make sure we are move out of this block.
2089
2175
auto &useState = dataflowState.useState ;
2090
2176
auto &applySiteToPromotedArgIndices =
0 commit comments