|
32 | 32 | #include "swift/Basic/SourceLoc.h"
|
33 | 33 | #include "swift/Parse/Lexer.h"
|
34 | 34 | #include "swift/SIL/CFG.h"
|
| 35 | +#include "swift/SIL/InstructionUtils.h" |
35 | 36 | #include "swift/SIL/SILArgument.h"
|
36 | 37 | #include "swift/SIL/SILInstruction.h"
|
37 | 38 | #include "swift/SIL/Projection.h"
|
@@ -1122,6 +1123,54 @@ static void checkForViolationsInNoEscapeClosures(
|
1122 | 1123 | /*DiagnoseAsWarning=*/false);
|
1123 | 1124 | }
|
1124 | 1125 |
|
| 1126 | +#ifndef NDEBUG |
| 1127 | +// If a partial apply has @inout_aliasable arguments, it may only be used as |
| 1128 | +// a @noescape function type in a way that is recognized by |
| 1129 | +// DiagnoseStaticExclusivity. |
| 1130 | +static void checkNoEscapePartialApply(PartialApplyInst *PAI) { |
| 1131 | + SmallVector<Operand *, 8> uses(PAI->getUses()); |
| 1132 | + while (!uses.empty()) { |
| 1133 | + Operand *oper = uses.pop_back_val(); |
| 1134 | + SILInstruction *user = oper->getUser(); |
| 1135 | + |
| 1136 | + if (isIncidentalUse(user) || onlyAffectsRefCount(user)) |
| 1137 | + continue; |
| 1138 | + |
| 1139 | + if (SingleValueInstruction *copy = getSingleValueCopyOrCast(user)) { |
| 1140 | + uses.append(copy->getUses().begin(), copy->getUses().end()); |
| 1141 | + continue; |
| 1142 | + } |
| 1143 | + if (auto apply = isa<ApplySite>(user)) { |
| 1144 | + SILValue arg = oper->get(); |
| 1145 | + auto ArgumentFnType = arg->getType().getAs<SILFunctionType>(); |
| 1146 | + if (ArgumentFnType && ArgumentFnType->isNoEscape()) |
| 1147 | + continue; |
| 1148 | + |
| 1149 | + llvm::dbgs() << "Argument must be @noescape function type: " << *arg; |
| 1150 | + llvm_unreachable("A partial_apply with @inout_aliasable may only be " |
| 1151 | + "used as a @noescape function type argument."); |
| 1152 | + } |
| 1153 | + auto *store = dyn_cast<StoreInst>(user); |
| 1154 | + if (store && oper->getOperandNumber() == StoreInst::Src) { |
| 1155 | + if (auto *PBSI = dyn_cast<ProjectBlockStorageInst>(store->getDest())) { |
| 1156 | + SILValue storageAddr = PBSI->getOperand(); |
| 1157 | + // The closure is stored to block storage. Recursively visit all |
| 1158 | + // uses of any initialized block storage values derived from this |
| 1159 | + // storage address.. |
| 1160 | + for (Operand *oper : storageAddr->getUses()) { |
| 1161 | + if (auto *IBS = dyn_cast<InitBlockStorageHeaderInst>(oper->getUser())) |
| 1162 | + uses.append(IBS->getUses().begin(), IBS->getUses().end()); |
| 1163 | + } |
| 1164 | + continue; |
| 1165 | + } |
| 1166 | + } |
| 1167 | + llvm::dbgs() << "Unexpected partial_apply use: " << *user; |
| 1168 | + llvm_unreachable("A partial_apply with @inout_aliasable may only be " |
| 1169 | + "used as a @noescape function type argument."); |
| 1170 | + } |
| 1171 | +} |
| 1172 | +#endif |
| 1173 | + |
1125 | 1174 | static void checkStaticExclusivity(SILFunction &Fn, PostOrderFunctionInfo *PO,
|
1126 | 1175 | AccessSummaryAnalysis *ASA) {
|
1127 | 1176 | // The implementation relies on the following SIL invariants:
|
@@ -1229,6 +1278,21 @@ static void checkStaticExclusivity(SILFunction &Fn, PostOrderFunctionInfo *PO,
|
1229 | 1278 | ConflictingAccesses);
|
1230 | 1279 | continue;
|
1231 | 1280 | }
|
| 1281 | +#ifndef NDEBUG |
| 1282 | + // FIXME: Once AllocBoxToStack is fixed to correctly set noescape |
| 1283 | + // closure types, move this PartialApply verification into the |
| 1284 | + // SILVerifier to better pinpoint the offending pass. |
| 1285 | + if (auto *PAI = dyn_cast<PartialApplyInst>(&I)) { |
| 1286 | + ApplySite apply(PAI); |
| 1287 | + if (llvm::any_of(range(apply.getNumArguments()), |
| 1288 | + [apply](unsigned argIdx) { |
| 1289 | + return apply.getArgumentConvention(argIdx) |
| 1290 | + == SILArgumentConvention::Indirect_InoutAliasable; |
| 1291 | + })) { |
| 1292 | + checkNoEscapePartialApply(PAI); |
| 1293 | + } |
| 1294 | + } |
| 1295 | +#endif |
1232 | 1296 | // Sanity check to make sure entries are properly removed.
|
1233 | 1297 | assert((!isa<ReturnInst>(&I) || Accesses.size() == 0) &&
|
1234 | 1298 | "Entries were not properly removed?!");
|
|
0 commit comments