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